Skip to content

React

Компоненты

export default function Button() {
return <button>Click me</button>;
}

Вставка переменных в шаблон

export const HomePage = () => {
const number = 8;
function fibonacci(n) {
if (n <= 1) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
return (
<div>
<p>Это число: {number}</p>
<p>Это число умноженное на 2: {number * 2}</p>
<p>Это число фибоначчи: {fibonacci(number)}</p>
</div>
);
};

Рендеринг коллекций

export const HomePage = () => {
const students = [
{ id: 1, fullName: "John", age: 20, gpa: 3.5 },
{ id: 2, fullName: "Jane", age: 21, gpa: 3.7 },
{ id: 3, fullName: "Bob", age: 19, gpa: 3.2 },
{ id: 4, fullName: "Alice", age: 22, gpa: 3.8 },
];
return (
<div>
<h1>Студенты</h1>
<ul>
{students.map((student) => (
<li key={student.id}>
{student.fullName} - {student.age} лет, {student.gpa} GPA
</li>
))}
</ul>
</div>
);
};

Props

props (сокращение от “properties”) — это механизм передачи данных от родительского компонента к дочернему.Простыми словами, props — это способ передавать данные напрямую из одного компонента в другой.

У нас есть один компонент, в котором хранятся данные (он называется родительским), и мы передаём их в другой компонент (дочерний компонент). Дочерний компонент получает эти данные в виде свойств (props) и может их использовать, но не может их изменять.

Это похоже на передачу аргументов в функцию:

export default function App() {
return <Hello message="Мир" />;
}
function Hello(props: { message: string }) {
return <h1>Привет, {props.message}!</h1>;
}

Здесь message=“Мир” — это prop, который передаётся из App в Hello.

Примеры как можно использвать props :

1 Передача числа и вычисления

function Square(props: { num: number }) {
return <h1>Квадрат числа {props.num}: {props.num ** 2}</h1>;
}
export default function App() {
return <Square num={5} />;
}

🔍 Что происходит ?

Здесь мы передали число в компонент Square.

  1. {props.num} — здесь он покажет само переданное число.
  2. {props.num ** 2} — здесь происходит возведение числа в квадрат.

2 Передача массива и рендер списка

function List(props: { items: string[] }) {
return (
<ul>
{props.items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
export default function App() {
return <List items={["Яблоко", "Груша", "Банан"]} />;
}

🔍 Что происходит ?

В компоненте App определён компонент List , внутри которого: Принимается пропс items — это массив строк [“Яблоко”, “Груша”, “Банан”]. В компоненте List создаётся <ul>

  • item — это текущий элемент массива (“Яблоко”, “Груша”, “Банан”).
  • index — это его порядковый номер.
  • key={index} — это уникальный ключ, который нужен React для корректного обновления списка.

🟢 Плюсы:

Такой подход позволяет рендерить большое количество данных динамически.

3 Передача функции как пропса

function Button(props: { onClick: () => void }) {
return <button onClick={props.onClick}>Нажми меня</button>;
}
export default function App() {
function showAlert() {
alert("Кнопка нажата!");
}
return <Button onClick={showAlert} />;
}

🔍 Что происходит ?

В компоненте App определён компонент Button, внутри которого:

  1. Принимается пропс onClick — это функция, которая будет выполняться при нажатии на кнопку.
  2. Внутри компонента Button создаётся <button> с обработчиком onClick={props.onClick}.
  3. В компоненте App объявляется функция showAlert, которая вызывает alert("Кнопка нажата!").
  4. Компонент Button используется в App, и ему передаётся showAlert в качестве onClick.

Когда пользователь нажимает кнопку:

  • props.onClick срабатывает и вызывает showAlert.
  • Появляется всплывающее окно (alert) с текстом “Кнопка нажата!”.

🟢 Плюсы:

Компоненты можно переиспользовать с разными функциями, просто передавая их через props.

4 Передача объектов в props

function UserCard(props: { user: { name: string; age: number } }) {
return <h1>{props.user.name}, {props.user.age} лет</h1>;
}
export default function App() {
const userInfo = { name: "Bob", age: 25 };
return <UserCard user={userInfo} />;
}

🔍 Что происходит ?

В компоненте App определён компонент UserCard, внутри которого:

  1. Принимается пропс user — это объект с двумя свойствами:

    • name (строка) — имя пользователя.
    • age (число) — возраст пользователя.
  2. Внутри компонента UserCard рендерится заголовок <h1>, который показывает:

    • props.user.name — имя пользователя.
    • props.user.age — возраст пользователя.
  3. В компоненте App создаётся объект userInfo, содержащий:

    • name: “Bob”
    • age: 25

Компонент UserCard используется в App, и ему передаётся объект userInfo через проп user.

♻️ Во время рендера:

Передаётся объект userInfo в UserCard. Он в свою очередь обращается к props.user.name и props.user.age. И отображается заголовок <h1>Bob, 25 лет</h1>

🟢 Плюсы:

Такой код делает компоненты гибкими, так как он может отображть разных пользователей и разные данные, просто передавая в него разные объекты.

5 Деструктуризация props для удобства

function UserCard({ name, age }: { name: string; age: number }) {
return <h1>{name}, {age} лет</h1>;
}
export default function App() {
return <UserCard name="Анна" age={22} />;
}

💡 Что изменилось?

  • В параметрах функции сразу извлекаем name и age из props.
  • Теперь можно использовать name и age напрямую, без props..

🟢 Плюсы:

  • Код становится чище и читабельнее.
  • Не нужно каждый раз писать props. перед именем переменной

6 В props можно передавать любые типы данных

Тип данныхПример использования
Строки<Title text="Привет" />
Числа<Age value={30} />
Булевы значения<Checkbox checked={true} />
Массивы<List items={['Apple', 'Banana']} />
Объекты<User data={{ name: 'Анна', age: 22 }} />
Функции (колбэки)<Button onClick={handleClick} />

Главное правило: props позволяют компонентам взаимодействовать, но сами они неизменяемые (read-only).

Props — это основа взаимодействия между компонентами в React. Они позволяют передавать данные и делают компоненты гибкими и переиспользуемыми.

Hooks

Hooks (хуки) — это функции, которые позволяют использовать состояние (state) и другие возможности React без написания классов. Они появились в React 16.8 и сделали функциональные компоненты мощными и удобными. Простыми словами это заготовленые функции с помощью которых мы можем дотянуться до состояния своего приложения как-бы цеплясь крюком (от этого и название) и менять его.

🚀 Полный список React-хуков

ХукОписание
useStateДобавляет состояние в функциональный компонент.
useEffectВыполняет побочные эффекты (запросы, подписки, таймеры).
useContextПозволяет использовать глобальное состояние через React.Context.
useRefСоздает ссылку на DOM-элемент или хранит изменяемое значение.
useMemoОптимизирует вычисления, запоминая их результат.
useCallbackЗапоминает функцию, чтобы она не пересоздавалась при каждом рендере.
useReducerАльтернатива useState для сложной логики состояний.
useLayoutEffectРаботает как useEffect, но запускается синхронно после всех изменений DOM.
useImperativeHandleПозволяет управлять ref, переданным в компонент.
useDebugValueИспользуется для отображения отладочной информации в React DevTools.
useIdГенерирует уникальный ID (полезно для привязки элементов).
useTransitionПозволяет делать переходы между состояниями более плавными.
useDeferredValueПозволяет откладывать обновление значения для плавности интерфейса.
useSyncExternalStoreИспользуется для работы с внешними состояниями (например, глобальным состоянием в Redux).
useInsertionEffectПозволяет вставлять стили перед рендерингом компонента.

🔹 Основные хуки выделены жирным.

useState

import { useState } from "react";
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>Счетчик: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
};
  • count — текущее значение
  • setCount — функция обновления

useEffect

1. Запуск эффекта при каждом рендере (без зависимостей)

import { useState, useEffect } from "react";
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Компонент обновился!");
});
return (
<div>
<p>Счетчик: {count}</p>
<button onClick={() => setCount(count + 1)}>Увеличить</button>
</div>
);
}

🔍 Что происходит?

  • useEffect вызывается после каждого рендера (в том числе после обновления состояния count).
  • В консоли после каждого клика будет сообщение “Компонент обновился!”.

🔴 Минус: может вызывать ненужные вычисления, если эффект не должен запускаться при каждом рендере.

2. Запуск эффекта один раз (при монтировании компонента)

Если передать пустой массив зависимостей [], эффект выполнится только один раз – при первом рендере.

import { useEffect } from "react";
function HelloWorld() {
useEffect(() => {
console.log("Компонент был смонтирован!");
}, []);
return <p>Привет, мир!</p>;
}

🔍 Что происходит?

  • Сообщение “Компонент был смонтирован!” появится только один раз после монтирования.

📌 Применение:

  • Запрос данных (fetch)
  • Подписка на глобальные события (window.addEventListener)
  • Установка начального состояния (localStorage.getItem)

3. Запуск эффекта при изменении зависимостей

Если передать массив зависимостей, эффект будет срабатывать только при изменении этих зависимостей.

import { useState, useEffect } from "react";
function UserProfile({ userId }) {
const [userData, setUserData] = useState(null);
useEffect(() => {
console.log(`Загружаем данные для пользователя ${userId}`);
fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
.then((response) => response.json())
.then((data) => setUserData(data));
}, [userId]); // Запускается только при изменении userId
return <p>Пользователь: {userData?.name || "Загрузка..."}</p>;
}

🔍 Что происходит?

  • useEffect сработает при первом рендере и каждый раз, когда изменяется userId.
  • Если userId не меняется — эффект не выполняется повторно.

📌 Применение:

  • Переключение между пользователями (например, при выборе ID)
  • Запрос новых данных при изменении параметров
  • Обновление стилей или заголовков страницы

4. Очистка эффекта (Cleanup)

Некоторые эффекты (например, таймеры или подписки) требуют очистки перед размонтированием компонента или перед повторным вызовом эффекта.

import { useState, useEffect } from "react";
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds((prev) => prev + 1);
}, 1000);
return () => {
clearInterval(interval); // Очистка таймера при размонтировании
console.log("Таймер остановлен!");
};
}, []); // Таймер запускается только при монтировании
return <p>Секунды: {seconds}</p>;
}

🔍 Что происходит?

  • setInterval запускается при монтировании.
  • Когда компонент размонтируется, вызывается clearInterval, чтобы предотвратить утечки памяти.

📌 Применение:

  • Отписка от событий (window.removeEventListener)
  • Очистка таймеров (clearTimeout, clearInterval)
  • Закрытие соединений (WebSocket, AbortController)

5. Очистка перед каждым новым вызовом

Если эффект зависит от переменной, React сначала очистит предыдущий эффект перед вызовом нового.

import { useState, useEffect } from "react";
function MouseTracker() {
const [position, setPosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const updateMousePosition = (event) => {
setPosition({ x: event.clientX, y: event.clientY });
};
window.addEventListener("mousemove", updateMousePosition);
return () => {
window.removeEventListener("mousemove", updateMousePosition);
console.log("Очистка: отписка от mousemove");
};
}, []);
return (
<p>
Координаты мыши: {position.x}, {position.y}
</p>
);
}

🔍 Что происходит?

  • При монтировании подписка window.addEventListener(“mousemove”, updateMousePosition).
  • Если компонент размонтируется, вызывается removeEventListener, чтобы избежать утечек памяти.

📌 Применение:

  • Отписка от глобальных событий
  • Удаление старых подписок перед добавлением новых
  • Завершение анимаций или запросов

useRef

import { useRef } from "react";
function Counter() {
const countRef = useRef(0);
useEffect(() => {
console.log(countRef.current);
}, [countRef.current]);
return (
<div>
<p>Счетчик: {countRef.current}</p>
<button onClick={() => countRef.current++}>+</button>
</div>
);
}

Кастомные хуки (Custom Hooks)

Так-же в React, можно написать свой собственный, кастомный хук, если нет нужного хука для решения задачи. Например давайте напишем хук который будет сохранять и извлекать данные из localStorage.

import { useState } from "react";
function useLocalStorage(key: string, initialValue: string) {
const [value, setValue] = useState(
localStorage.getItem(key) || initialValue
);
const setStoredValue = (newValue: string) => {
localStorage.setItem(key, newValue);
setValue(newValue);
};
return [value, setStoredValue] as const;
}

📌 Что здесь происходит?

  1. Инициализация состояния (useState)`

    • value — текущее значение из localStorage, если оно есть, иначе используется initialValue.
    • setValue — функция для обновления состояния.
  2. Функция setStoredValue

    • Обновляет значение в localStorage.
    • Вызывает setValue для обновления состояния в React.
  3. Возвращение значения и функции обновления

    • return [value, setStoredValue] as const;
    • Это массив, который содержит само значение и функцию его обновления.
    • as const делает массив кортежем (чтобы React мог точно определить его структуру).

Теперь можно использовать этот хук в других компонентах:

// Здесь нужно указать импорт из файла где создали этот хук
function App() {
const [name, setName] = useLocalStorage("username", "Гость");
return (
<div>
<h1>Привет, {name}!</h1>
<button onClick={() => setName("Bob")}>Сменить имя</button>
</div>
);
}

🟢 Плюсы хуков:

✅ Хуки сделали React проще и мощнее.

✅ Они позволяют работать с состоянием и эффектами.

✅ Использование хуков делает код функциональных компонентов чище и читаемее.

🚀 React Hooks — это фундамент современных React-приложений!