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.
{props.num}
— здесь он покажет само переданное число.{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, внутри которого:
- Принимается пропс
onClick
— это функция, которая будет выполняться при нажатии на кнопку. - Внутри компонента Button создаётся
<button>
с обработчикомonClick={props.onClick}
. - В компоненте App объявляется функция
showAlert
, которая вызываетalert("Кнопка нажата!")
. - Компонент 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
, внутри которого:
-
Принимается пропс
user
— это объект с двумя свойствами:- name (строка) — имя пользователя.
- age (число) — возраст пользователя.
-
Внутри компонента
UserCard
рендерится заголовок<h1>
, который показывает:props.user.name
— имя пользователя.props.user.age
— возраст пользователя.
-
В компоненте 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;}
📌 Что здесь происходит?
-
Инициализация состояния (useState)`
value
— текущее значение изlocalStorage
, если оно есть, иначе используетсяinitialValue
.setValue
— функция для обновления состояния.
-
Функция
setStoredValue
- Обновляет значение в
localStorage
. - Вызывает
setValue
для обновления состояния в React.
- Обновляет значение в
-
Возвращение значения и функции обновления
- 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-приложений!