Перевірка знань по темі "React"

1. Що таке React?

React — це JavaScript бібліотека для створення користувацького інтерфейсу. Вона дозволяє будувати UI з компонентів та ефективно оновлювати DOM за допомогою Virtual DOM.

import React from 'react';
import ReactDOM from 'react-dom';

function App() {
  return <h1>Hello React!</h1>;
}

ReactDOM.render(<App />, document.getElementById('root'));

Best practice: завжди розбивай UI на маленькі компоненти для повторного використання.

2. Що таке JSX?

JSX — це синтаксичне розширення для JavaScript, що дозволяє писати HTML-подібний код у JS. React трансформує JSX у виклики React.createElement.

const element = <h1>Hello, JSX!</h1>;

Правило: JSX повинен бути обгорнутий у один кореневий елемент.

3. Функціональні та класові компоненти

Функціональні компоненти — це прості функції, що повертають JSX. Класові компоненти розширюють React.Component і мають додаткові можливості, як state і lifecycle.

// Функціональна
function Greeting() {
  return <h2>Hello!</h2>;
}

// Класова
class GreetingClass extends React.Component {
  render() {
    return <h2>Hello Class!</h2>;
  }
}

Best practice: з React 16+ рекомендується використовувати функціональні компоненти з hooks.

4. Props

Props — це властивості, які передаються компоненту для налаштування його поведінки. Вони є тільки для читання.

function Welcome(props) {
  return <h2>Hello, {props.name}</h2>;
}

<Welcome name="Alice" />;

Правило: ніколи не змінюйте props всередині компонента.

5. State

State — це внутрішній стан компонента, який може змінюватися з часом і викликає повторний рендеринг компонента.

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  );
}

Best practice: тримайте state мінімальним і локалізованим.

6. Події у React

Події у React обробляються через camelCase атрибути, наприклад onClick, onChange.

function Button() {
  const handleClick = () => alert('Clicked!');
  return <button onClick={handleClick}>Click me</button>;
}

Правило: не викликайте функцію у JSX без обгортки, інакше вона виконається одразу.

7. Умовний рендеринг

React дозволяє умовно рендерити елементи через ? : або &&.

// з ? :
const isLoggedIn = true;
return isLoggedIn ? <p>Welcome back!</p> : <p>Please sign in.</p>

// з &&
return <div>{isLoggedIn && <p>Welcome back!</p>}</div>;

Best practice: використовуйте ternary, якщо є else, && для коротких перевірок.

8. Fragment у React

React.Fragment дозволяє групувати елементи без додаткового DOM-вузла.

return (
  <>
    <h1>Title</h1>
    <p>Description</p>
  </>
);

Правило: зберігає DOM чистим і зменшує непотрібні div.

9. Коментарі у JSX

Коментарі у JSX пишуться всередині фігурних дужок.

return (
  <div>
    {/* Це коментар */}
    <p>Text</p>
  </div>
);
10. Атрибути у JSX

Деякі HTML-атрибути мають camelCase назви у JSX, наприклад className, htmlFor.

<input type="text" className="input" readOnly />
<label htmlFor="input">Label</label>
11. Передача функцій як props

Можна передавати функції з батьківського компонента в дочірній через props, щоб дочірній компонент викликав дії батька.

function Child({ onClick }) {
  return <button onClick={onClick}>Click me</button>;
}

function Parent() {
  const handleClick = () => alert('Clicked from parent!');
  return <Child onClick={handleClick} />;
}

Best practice: передавай тільки потрібні функції та уникай створення нових функцій всередині render без необхідності.

12. Контрольовані компоненти

Контрольований компонент зберігає значення інпуту у state і керує ним через onChange.

function ControlledInput() {
  const [value, setValue] = React.useState('');
  return <input value={value} onChange={e => setValue(e.target.value)} />;
}

Правило: state є єдиним джерелом істини для значень інпутів.

13. Неконтрольовані компоненти

Неконтрольований інпут використовує ref для доступу до значення без збереження його у state.

function UncontrolledInput() {
  const inputRef = React.useRef();
  const handleClick = () => alert(inputRef.current.value);
  return <div>
    <input ref={inputRef} />
    <button onClick={handleClick}>Show Value</button>
  </div>;
}

Best practice: використовуй неконтрольовані компоненти лише для простих форм або інтеграції зі сторонніми бібліотеками.

14. Вставка виразів у JSX

У JSX можна вставляти будь-які JS-вирази у фігурних дужках.

const name = 'Alice';
return <h1>Hello, {name}!</h1>;

Правило: у дужках можна писати вирази, але не statements (if, for, etc.).

15. Коментарі у JSX

Коментарі повинні бути всередині фігурних дужок: {/* коментар */}

return (
  <div>
    {/* Це коментар */}
    <p>Text</p>
  </div>
);
16. Умовний рендеринг з &&

Зручно використовувати для рендерингу одного елемента за умови true.

const isLoggedIn = true;
return <div>
  {isLoggedIn && <p>Welcome back!</p>}
</div>;

Правило: && повертає false, якщо умова невірна, і React нічого не рендерить.

17. Умовний рендеринг з ? :

Для вибору між двома елементами використовуйте тернарний оператор.

return <div>
  {isLoggedIn ? <p>Welcome back!</p> : <p>Please sign in.</p>}
</div>;
18. Вставка списків у JSX

Списки рендеряться через map(), важливо додавати унікальний key для кожного елемента.

const fruits = ['Apple', 'Banana', 'Cherry'];
return <ul>
  {fruits.map((fruit, index) => <li key={index}>{fruit}</li>)}
</ul>;

Best practice: використовуйте стабільні ключі, а не індекси, коли можливо.

19. Атрибути HTML у JSX

Багато атрибутів змінюють написання у JSX (camelCase), наприклад className, htmlFor.

<input type="text" className="input" readOnly />
<label htmlFor="input">Label</label>
20. Best practices основ React
  • Розбивайте UI на маленькі, повторно використовувані компоненти.
  • Використовуйте state лише там, де потрібно відстежувати дані.
  • Props не можна змінювати всередині компонентів.
  • Функціональні компоненти + hooks — сучасний стандарт.
21. Списки у React

Списки рендеряться за допомогою функції map(). Важливо вказувати унікальний key для кожного елемента.

const fruits = ['Apple', 'Banana', 'Cherry'];
return <ul>
  {fruits.map((fruit) => <li key={fruit}>{fruit}</li>)}
</ul>;

Правило: не використовуйте індекси як ключі, якщо порядок елементів може змінюватися.

22. Умовний рендеринг у списках

Можна рендерити список лише за умови, якщо він не порожній.

return <ul>
  {fruits.length > 0
    ? fruits.map(f => <li key={f}>{f}</li>)
    : <li>Список порожній</li>}
</ul>;
23. Контрольовані форми

Контрольований інпут зберігає значення у state і оновлює його через onChange.

function ControlledInput() {
  const [value, setValue] = React.useState('');
  return <input value={value} onChange={e => setValue(e.target.value)} />;
}
24. Неконтрольовані форми

Неконтрольований інпут використовує ref для доступу до значення без state.

function UncontrolledInput() {
  const inputRef = React.useRef();
  const handleClick = () => alert(inputRef.current.value);
  return <div>
    <input ref={inputRef} />
    <button onClick={handleClick}>Show</button>
  </div>;
}
25. Обробка подій у формах

Усі події у React обробляються через camelCase атрибути.

function Form() {
  const handleChange = e => console.log(e.target.value);
  return <input onChange={handleChange} />;
}
26. Кілька input у state

Можна зберігати значення кількох інпутів у одному об'єкті state.

function Form() {
  const [form, setForm] = React.useState({name:'', age:''});
  const handleChange = e => setForm({...form, [e.target.name]: e.target.value});
  return (
    <form>
      <input name="name" value={form.name} onChange={handleChange} />
      <input name="age" value={form.age} onChange={handleChange} />
    </form>
  );
}
27. Списки з компонентами

Можна створювати компонент для елементів списку та рендерити їх через map.

function Item({ value }) {
  return <li>{value}</li>;
}
function List() {
  const items = ['A', 'B', 'C'];
  return <ul>{items.map(v => <Item key={v} value={v} />)}</ul>;
}
28. Checkbox у формах

Контрольований checkbox керується через state.

function Checkbox() {
  const [checked, setChecked] = React.useState(false);
  return <input type="checkbox" checked={checked} onChange={e => setChecked(e.target.checked)} />;
}
29. Select у формах

Select елемент також може бути контрольованим через state.

function Select() {
  const [value, setValue] = React.useState('A');
  return (
    <select value={value} onChange={e => setValue(e.target.value)}>
      <option value="A">A</option>
      <option value="B">B</option>
    </select>
  );
}
30. preventDefault у формах

Для запобігання перезавантаженню сторінки при submit використовується e.preventDefault().

function Form() {
  const handleSubmit = e => {
    e.preventDefault();
    alert('Form submitted!');
  };
  return <form onSubmit={handleSubmit}><button type="submit">Submit</button></form>;
}
31. Контрольований textarea

Textarea у React може бути контрольованим компонентом через state.

function TextArea() {
  const [text, setText] = React.useState('');
  return <textarea value={text} onChange={e => setText(e.target.value)} />;
}
32. Неконтрольований textarea

Неконтрольований textarea використовує ref для доступу до значення.

function TextArea() {
  const ref = React.useRef();
  const handleClick = () => alert(ref.current.value);
  return <div>
    <textarea ref={ref} />
    <button onClick={handleClick}>Show</button>
  </div>;
}
33. Додавання динамічних полів форми

Можна додавати input елементи динамічно за допомогою state та map.

function DynamicForm() {
  const [inputs, setInputs] = React.useState(['']);
  const addInput = () => setInputs([...inputs, '']);
  return <div>
    {inputs.map((val, i) => <input key={i} value={val} />)}
    <button onClick={addInput}>Add</button>
  </div>;
}
34. Обробка числових полів

Інпут type="number" можна контролювати через state і приводити значення до числа.

function NumberInput() {
  const [num, setNum] = React.useState(0);
  return <input type="number" value={num} onChange={e => setNum(Number(e.target.value))} />;
}
35. Select з масиву опцій

Можна генерувати опції select динамічно через map.

const options = ['A', 'B', 'C'];
function SelectList() {
  const [value, setValue] = React.useState('A');
  return (
    <select value={value} onChange={e => setValue(e.target.value)}>
      {options.map((opt, i) => <option key={i} value={opt}>{opt}</option>)}
    </select>
  );
}
36. Валідація форми

Можна перевіряти значення полів перед відправкою форми і показувати повідомлення користувачу.

function Form() {
  const [name, setName] = React.useState('');
  const handleSubmit = e => {
    e.preventDefault();
    if(name.trim() === '') alert('Name is required');
  };
  return <form onSubmit={handleSubmit}>
    <input value={name} onChange={e => setName(e.target.value)} />
    <button type="submit">Submit</button>
  </form>;
}
37. Кілька checkbox

Можна зберігати стан декількох checkbox у масиві.

function Checkboxes() {
  const [checked, setChecked] = React.useState([]);
  const toggle = value => {
    setChecked(prev => prev.includes(value) ? prev.filter(v => v!==value) : [...prev, value]);
  };
  return ['A','B','C'].map(val =>
    <label key={val}>
      <input type="checkbox" checked={checked.includes(val)} onChange={() => toggle(val)} /> {val}
    </label>
  );
}
38. Radio buttons

Контрольований radio button вибирає одну опцію з групи.

function Radios() {
  const [selected, setSelected] = React.useState('A');
  return ['A','B','C'].map(val =>
    <label key={val}>
      <input type="radio" value={val} checked={selected===val} onChange={e => setSelected(e.target.value)} /> {val}
    </label>
  );
}
39. Submit без перезавантаження

Використання e.preventDefault() дозволяє обробляти submit без reload.

function Form() {
  const handleSubmit = e => {
    e.preventDefault();
    alert('Form submitted without reload!');
  };
  return <form onSubmit={handleSubmit}>
    <button type="submit">Submit</button>
  </form>;
}
40. Best practices форм та списків
  • Завжди використовуйте унікальні key для списків.
  • Керовані форми простіші для відстеження стану.
  • Обробляйте submit через preventDefault.
  • Валідуйте поля перед відправкою.
41. useState

useState дозволяє додавати локальний стан у функціональні компоненти.

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  return <div>
    <p>Count: {count}</p>
    <button onClick={() => setCount(count + 1)}>+</button>
  </div>;
}

Правило: не змінюйте state напряму, використовуйте setCount.

42. useEffect

useEffect дозволяє виконувати побічні ефекти, наприклад запити до API або підписки.

import React, { useState, useEffect } from 'react';

function Timer() {
  const [seconds, setSeconds] = useState(0);
  useEffect(() => {
    const interval = setInterval(() => setSeconds(s => s + 1), 1000);
    return () => clearInterval(interval); // cleanup
  }, []);
  return <p>Seconds: {seconds}</p>;
}

Правило: завжди очищайте підписки у return для уникнення memory leaks.

43. useRef

useRef зберігає mutable значення або DOM-елементи між рендерами.

import React, { useRef } from 'react';

function FocusInput() {
  const inputRef = useRef();
  return <div>
    <input ref={inputRef} />
    <button onClick={() => inputRef.current.focus()}>Focus</button>
  </div>;
}

Best practice: useRef не викликає ререндер при зміні значення.

44. useMemo

useMemo запам'ятовує результат обчислень для оптимізації продуктивності.

import React, { useMemo, useState } from 'react';

function Expensive({ num }) {
  const compute = useMemo(() => {
    console.log('Computing...');
    return num * 2;
  }, [num]);
  return <p>Result: {compute}</p>;
}

Правило: використовуйте useMemo тільки для дорогих обчислень.

45. useCallback

useCallback запам'ятовує функцію між рендерами, щоб уникнути зайвих перерендерів дочірніх компонентів.

import React, { useState, useCallback } from 'react';

function Button({ onClick }) {
  console.log('Button render');
  return <button onClick={onClick}>Click</button>;
}

function Parent() {
  const [count, setCount] = useState(0);
  const handleClick = useCallback(() => setCount(c => c + 1), []);
  return <div>
    <Button onClick={handleClick} />
    <p>Count: {count}</p>
  </div>;
}
46. useContext

useContext дозволяє отримати значення з Context без передачі через props.

import React, { createContext, useContext } from 'react';

const ThemeContext = createContext('light');

function Child() {
  const theme = useContext(ThemeContext);
  return <p>Theme: {theme}</p>;
}

function Parent() {
  return <ThemeContext.Provider value="dark">
    <Child />
  </ThemeContext.Provider>;
}
47. Кастомні хуки

Кастомні хуки — це функції, що використовують інші хуки і повертають логіку для повторного використання.

import React, { useState, useEffect } from 'react';

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);
  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);
  return width;
}

function App() {
  const width = useWindowWidth();
  return <p>Width: {width}</p>;
}
48. useLayoutEffect

useLayoutEffect виконується синхронно після DOM оновлення, до відображення на екрані.

import React, { useLayoutEffect, useRef } from 'react';

function Measure() {
  const ref = useRef();
  useLayoutEffect(() => {
    console.log(ref.current.getBoundingClientRect());
  }, []);
  return <div ref={ref}>Measure me</div>;
}
49. useImperativeHandle

useImperativeHandle дозволяє налаштувати, що повертає ref при використанні forwardRef.

import React, { useRef, forwardRef, useImperativeHandle } from 'react';

const Input = forwardRef((props, ref) => {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus()
  }));
  return <input ref={inputRef} />;
});

function App() {
  const ref = useRef();
  return <div>
    <Input ref={ref} />
    <button onClick={() => ref.current.focus()}>Focus</button>
  </div>;
}
50. useReducer

useReducer — альтернатива useState для складних станів із діями.

import React, { useReducer } from 'react';

function reducer(state, action) {
  switch(action.type) {
    case 'increment': return {count: state.count + 1};
    case 'decrement': return {count: state.count - 1};
    default: return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, {count:0});
  return <div>
    <p>Count: {state.count}</p>
    <button onClick={() => dispatch({type:'increment'})}>+</button>
    <button onClick={() => dispatch({type:'decrement'})}>-</button>
  </div>;
}
51. useDebugValue

useDebugValue дозволяє відображати інформацію для кастомних хуків у React DevTools.

import React, { useDebugValue } from 'react';

function useCustomHook(value) {
  useDebugValue(value ? 'Has Value' : 'No Value');
  return value;
}
52. useDeferredValue

useDeferredValue дозволяє відкласти оновлення частини UI для кращої продуктивності.

import React, { useState, useDeferredValue } from 'react';

function Search() {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  return <input value={query} onChange={e => setQuery(e.target.value)} />;
}
53. useTransition

useTransition допомагає позначити оновлення як низькоприоритетні для плавного UI.

import React, { useState, useTransition } from 'react';

function App() {
  const [isPending, startTransition] = useTransition();
  const [value, setValue] = useState(0);

  const handleClick = () => {
    startTransition(() => setValue(v => v + 1));
  };

  return <div>
    <button onClick={handleClick}>Increment</button>
    <p>Value: {value}</p>
  </div>;
}
54. useId

useId генерує унікальний id для елементів, зручний для label та input.

import React, { useId } from 'react';

function Input() {
  const id = useId();
  return <div>
    <label htmlFor={id}>Name</label>
    <input id={id} />
  </div>;
}
55. useSyncExternalStore

useSyncExternalStore використовується для синхронізації з зовнішніми станами (store) у React 18+.

import { useSyncExternalStore } from 'react';

function useStore(store) {
  return useSyncExternalStore(store.subscribe, () => store.getState());
}
56. useEffect cleanup

Функція, яку повертає useEffect, використовується для очищення ефектів (event listeners, таймери).

useEffect(() => {
  const id = setInterval(() => console.log('Tick'), 1000);
  return () => clearInterval(id);
}, []);
57. useState з функцією ініціалізації

Можна передати функцію для початкового стану, щоб обчислення відбулося лише один раз.

const [value, setValue] = useState(() => expensiveComputation());
58. useEffect залежності

Масив залежностей визначає, коли ефект повторно виконується.

useEffect(() => {
  console.log(value);
}, [value]); // ефект виконується при зміні value
59. Порядок хуків

Хуки завжди повинні викликатися в одному порядку всередині компоненту або кастомного хуку.

// Правильно
useState();
useEffect();

// Неправильно
if(condition) useState(); // ❌
60. Best practices хуків
  • Використовуйте функціональні компоненти з хуками.
  • Дотримуйтесь правил виклику хуків (не всередині умов або циклів).
  • Використовуйте useMemo та useCallback для оптимізації складних обчислень або ререндерів.
  • Чистіть ефекти через return у useEffect.
  • Виносьте логіку у кастомні хуки для повторного використання.
61. React Router - BrowserRouter

BrowserRouter обгортає додаток і дозволяє використовувати маршрути.

import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return <BrowserRouter>
    <Routes>
      <Route path="/" element=<Home /> />
      <Route path="/about" element=<About /> />
    </Routes>
  </BrowserRouter>;
}
62. Route та element

Route визначає шлях і компонент, який рендериться через element.

<Route path="/contact" element=<Contact /> />
63. useParams

useParams дозволяє отримати параметри з URL.

import { useParams } from 'react-router-dom';

function User() {
  const { id } = useParams();
  return <p>User ID: {id}</p>;
}
64. useNavigate

useNavigate дозволяє програмно переміщатися між сторінками.

import { useNavigate } from 'react-router-dom';

function Home() {
  const navigate = useNavigate();
  return <button onClick={() => navigate('/about')}>Go to About</button>;
}
65. useLocation

useLocation дає доступ до об'єкта location (path, search, state).

import { useLocation } from 'react-router-dom';

function Page() {
  const location = useLocation();
  return <p>Current path: {location.pathname}</p>;
}
66. Context API - createContext

createContext створює глобальний контекст для передачі даних без props drilling.

import React, { createContext, useContext } from 'react';

const ThemeContext = createContext('light');

function Child() {
  const theme = useContext(ThemeContext);
  return <p>Theme: {theme}</p>;
}

function App() {
  return <ThemeContext.Provider value="dark">
    <Child />
  </ThemeContext.Provider>;
}
67. Context Provider та Consumer

Provider дає значення, Consumer або useContext отримує його.

<ThemeContext.Provider value="dark">
  <Child />
</ThemeContext.Provider>;
68. Redux - основи

Redux управляє глобальним станом через store, actions та reducers.

import { createStore } from 'redux';

const initialState = { count: 0 };
function reducer(state = initialState, action) {
  switch(action.type) {
    case 'increment': return { count: state.count + 1 };
    default: return state;
  }
}
const store = createStore(reducer);
69. Redux - connect та useSelector/useDispatch

useSelector читає стан, useDispatch відправляє дії.

import { useSelector, useDispatch } from 'react-redux';

function Counter() {
  const count = useSelector(state => state.count);
  const dispatch = useDispatch();
  return <div>
    <p>Count: {count}</p>
    <button onClick={() => dispatch({type:'increment'})}>+</button>
  </div>;
}
70. Zustand - базовий стан

Zustand - легкий глобальний state management для React.

import create from 'zustand';

const useStore = create(set => ({
  count: 0,
  increment: () => set(state => ({ count: state.count + 1 }))
}));

function Counter() {
  const { count, increment } = useStore();
  return <div>
    <p>Count: {count}</p>
    <button onClick={increment}>+</button>
  </div>;
}
71. React.lazy

React.lazy дозволяє завантажувати компонент асинхронно для оптимізації bundle.

import React, { lazy, Suspense } from 'react';

const LazyComponent = lazy(() => import('./LazyComponent'));

function App() {
  return <Suspense fallback=<p>Loading...</p>>
    <LazyComponent />
  </Suspense>;
}
72. Suspense fallback

fallback показує UI під час завантаження lazy-компоненту.

<Suspense fallback=<div>Loading...</div>>
  <LazyComponent />
</Suspense>
73. Nested routes

React Router дозволяє вкладені маршрути для компонентів.

<Routes>
  <Route path="/" element=<Layout />>
    <Route path="about" element=<About /> />
  </Route>
</Routes>
74. Redirect / Navigate

useNavigate дозволяє здійснювати перенаправлення після дії користувача.

const navigate = useNavigate();
<button onClick={() => navigate('/login')}>Go to Login</button>
75. Protected routes

Створюються для обмеження доступу до певних сторінок.

function Protected({ children }) {
  const auth = useAuth();
  return auth ? children : <Navigate to="/login" />;
}
76. Lazy load images / components

Використовуйте React.lazy та Suspense для компонентів, а loading="lazy" для зображень.

<img src="image.jpg" loading="lazy" />
77. useReducer + Context

Поєднання useReducer та Context дозволяє глобальний state без Redux.

const CountContext = createContext();

function reducer(state, action) {
  switch(action.type) {
    case 'inc': return { count: state.count+1 };
    default: return state;
  }
}

function App() {
  const [state, dispatch] = useReducer(reducer, {count:0});
  return <CountContext.Provider value={{state, dispatch}}>
    <Child />
  </CountContext.Provider>;
}
78. Global state з Zustand

Zustand дозволяє легко керувати глобальним станом без boilerplate.

import create from 'zustand';

const useStore = create(set => ({
  user: null,
  setUser: user => set({user})
}));

function Profile() {
  const {user, setUser} = useStore();
}
79. Suspense + Data fetching

Suspense можна використовувати для рендеру компонентів після завантаження даних.

const Resource = React.lazy(() => import('./DataComponent'));

<Suspense fallback=<div>Loading...</div>>
  <Resource />
</Suspense>
80. Best practices стану та маршрутизації
  • Використовуйте React Router для маршрутизації, а useNavigate для переходів.
  • Global state можна реалізувати через Context, Redux або Zustand.
  • Lazy та Suspense покращують продуктивність додатка.
  • Використовуйте Protected routes для авторизації.
  • Дотримуйтесь структурованого розподілу state між локальним і глобальним.
81. Portals

Portals дозволяють рендерити дочірні елементи поза DOM-структурою батьківського компоненту.

import ReactDOM from 'react-dom';

function Modal({ children }) {
  return ReactDOM.createPortal(
    <div className="modal">{children}</div>,
    document.getElementById('modal-root')
  );
}
82. Error Boundaries

Компоненти Error Boundary ловлять помилки в дочірніх компонентах та рендерять fallback UI.

class ErrorBoundary extends React.Component {
  state = { hasError: false };
  static getDerivedStateFromError(error) { return { hasError: true }; }
  render() { return this.state.hasError ? <h1>Something went wrong</h1> : this.props.children; }
}
83. useId для доступності

useId забезпечує унікальні id для input та label для кращої доступності.

const id = useId();
<label htmlFor={id}>Name</label>
<input id={id} />
84. Server Components

Server Components рендеряться на сервері, зменшуючи JS на клієнті.

export default function ServerComponent() {
  return <div>Rendered on server</div>;
}
85. Next.js Pages

Next.js використовує файли в папці pages для автоматичної маршрутизації.

// pages/index.js
export default function Home() {
  return <h1>Home Page</h1>;
}
86. Next.js API routes

API маршрути створюються в папці pages/api та повертають JSON.

// pages/api/hello.js
export default function handler(req, res) {
  res.status(200).json({ message: 'Hello API' });
}
87. React Testing Library - базове

Для тестування компонентів React використовується render та fireEvent.

import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';

test('increments counter', () => {
  render(<Counter />);
  fireEvent.click(screen.getByText('+'));
  expect(screen.getByText('Count: 1')).toBeInTheDocument();
});
88. React Profiler

Profiler вимірює час ререндеру компонентів.

<Profiler id="App" onRender={(id, phase, actualDuration) => console.log(actualDuration)}>
  <App />
</Profiler>
89. Memoization компонентів

React.memo запобігає перерендеру компоненту, якщо props не змінились.

const Button = React.memo(({onClick, label}) => <button onClick={onClick}>{label}</button>);
90. useTransition для плавного UI

Позначає оновлення як низькоприоритетні для плавнішого UI.

const [isPending, startTransition] = useTransition();
startTransition(() => setState(newValue));
91. useDeferredValue

Відкладає оновлення значення для оптимізації рендеру важких компонентів.

const deferredValue = useDeferredValue(value);
92. useId для форм

Генерує унікальні id для input та label, покращує доступність.

const id = useId();
<label htmlFor={id}>Email</label>
<input id={id} />
93. React Profiler API

Profiler дозволяє вимірювати час ререндеру компонентів для оптимізації продуктивності.

<Profiler id="App" onRender={(id, phase, actualDuration) => console.log(actualDuration)}>
  <App />
</Profiler>
94. Suspense для даних

Suspense може використовуватись не лише для lazy-компонентів, але й для асинхронних даних.

<Suspense fallback=<div>Loading data...</div>>
  <DataComponent />
</Suspense>
95. Concurrent React

Concurrent режим дозволяє React пріоритетно обробляти оновлення та покращує UX.

import { startTransition } from 'react';

startTransition(() => setState(newValue));
96. Оптимізація рендеру
  • Використовуйте React.memo для компонентів, які не повинні часто перерендерюватися.
  • useCallback для запобігання створенню нових функцій при кожному рендері.
  • useMemo для запобігання дорогим обчисленням на кожен рендер.
97. Error boundaries для компонентів

Використовуйте класові компоненти для ловлі помилок у дочірніх компонентах.

class ErrorBoundary extends React.Component {
  state = { hasError: false };
  static getDerivedStateFromError() { return { hasError: true }; }
  render() { return this.state.hasError ? <h1>Something went wrong</h1> : this.props.children; }
}
98. Portals для модальних вікон

Portals рендерять модальні компоненти поза основним DOM, у зручний контейнер.

ReactDOM.createPortal(<Modal />, document.getElementById('modal-root'));
99. Next.js оптимізація
  • Використовуйте getStaticProps та getServerSideProps для оптимізації рендеру.
  • Lazy loading компонентів та зображень.
  • Image optimization через next/image.
100. Best practices просунутих тем
  • Використовуйте Error Boundaries для стабільності додатка.
  • Lazy та Suspense для покращення UX та продуктивності.
  • Portals для модальних компонентів.
  • Concurrent features та useDeferredValue/useTransition для плавного UI.
  • Next.js – оптимізація серверного рендеру та статичних сторінок.
  • Тестування через React Testing Library та профайлинг рендерів.