Post

Срез 3

Изучение теории. Неделя 3

Срез 3

1. JS. Inheritance

1.1. Что такое прототипное наследование в JavaScript и как оно связано с цепочкой прототипов при поиске свойства у объекта?

Прототипное наследование — это способ передачи функционала между объектами через специальную ссылку [[Prototype]].

  • При обращении к свойству объекта, движок сначала ищет его в самом объекте.
  • Если свойство не найдено, поиск переходит к его прототипу, затем к прототипу прототипа и так далее — это и называется цепочкой прототипов.
  • Поиск продолжается до тех пор, пока свойство не будет найдено или цепочка не закончится на null.

1.2. Объясните различие между свойствами proto и prototype: где они находятся, для чего используются и как влияют на наследование

  • __proto__ есть у каждого объекта. Это фактическая ссылка, по которой объект ищет свойства у своего родителя в цепочке наследования.
  • prototype есть только у функций-конструкторов. Это шаблон, который функция выдает каждому новому объекту (в его __proto__) при создании через new.

Связь: Если вызвать const obj = new F(), то obj.__proto__ становится равен F.prototype.

1.3. Как бы вы устно описали подход к написанию полифила метода, который должен быть доступен всем массивам: куда его добавлять (прототип или как статический метод) и какие риски/ограничения у каждого варианта?

Добавлять нужно в Array.prototype, чтобы метод наследовался всеми экземплярами через цепочку прототипов.

  • Array.prototype: [].myMethod()
    • Риск: Конфликт имен с будущими стандартами JS и «загрязнение» глобальных объектов.
  • Статический метод: Array.myMethod([])
    • Ограничение: Недоступен экземплярам напрямую, это не полифил поведения массива, а просто утилита.

2. React. Render

2.1. Что делает ReactDOM.render() и какую роль он играет при отображении JSX на странице?

ReactDOM.render() связывает React и браузер. Он берет дерево React-элементов (JSX) и превращает его в настоящие DOM-узлы внутри указанного HTML-контейнера.

2.2. Как в JSX происходит вставка переменных и выражений, и какие типы значений React может корректно отрендерить без ошибок?

Вставка происходит через фигурные скобки { }. Внутри них можно писать любое валидное JavaScript-выражение.

React рендерит без ошибок:

  • Примитивы: Строки и числа (выводятся как текст).
  • Массивы: Рендерит каждый элемент списка последовательно.
  • JSX-элементы: Другие компоненты или HTML-теги.
  • Игнорируемые значения: true, false, null, undefined (не отображаются на экране, но не вызывают ошибок — удобно для условий).

Что вызовет ошибку:

  • Объекты: Прямой рендер обычного объекта

2.3. Объясните, как ReactDOM.render() (и механизм согласования React) обновляет уже отрисованные элементы: чем отличается виртуальный DOM от реального DOM и почему это обычно повышает производительность?

Обновление происходит через Virtual DOM — легкую копию реального DOM.

  1. Менять реальный DOM дорого и медленно. Виртуальный DOM — это просто данные в памяти, их сравнение происходит мгновенно.
  2. При изменении данных React создает новый Virtual DOM и сравнивает его с предыдущим(Diffing).
  3. React находит только изменившиеся узлы и применяет к реальному DOM минимально необходимые правки одним пакетом.

3. React. Fragments

3.1. Что такое React Fragment и для чего его обычно используют в JSX?

React Fragment — это специальный компонент, который позволяет группировать список дочерних элементов без создания лишнего узла (например, <div>) в DOM-дереве.

3.2. В каких ситуациях вы бы выбрали React.Fragment вместо оборачивания элементов в <div>, и какие практические последствия это имеет для DOM и стилизации?

Использование React.Fragment предпочтительно для:

  • Чистоты DOM: чтобы дерево элементов оставалось легким и в нем не было лишних оберток.
  • Сохранения структуры CSS: чтобы лишний тег не ломал сетки Flexbox или Grid.
  • Валидности HTML: чтобы не вставлять <div> туда, где по стандарту разрешены только специфичные теги (например, внутрь <table> или <ul>).

3.3. Зачем могут понадобиться ключи (key) при использовании Fragments, например при рендеринге списков, и чем отличается поведение при использовании явного с key от короткого синтаксиса <>...</>?

Ключи в Fragment нужны для идентификации элементов при рендеринге списков, чтобы React понимал, какие части интерфейса нужно обновить, а не перерисовывать полностью.

Главное отличие:

  • <React.Fragment key={...}>: поддерживает атрибут key, поэтому обязателен при использовании .map().
  • <>...</>: не поддерживает атрибуты (включая key), поэтому подходит только для разовой группировки элементов.

4. React. Fiber

4.1. Что такое Fiber в React и какую проблему в процессе reconciliation он помогает решать?

Fiber — это новый движок рендеринга React, который превращает процесс обновления интерфейса из непрерывного (стекового) в прерывистый.

Главная проблема, которую он решает — блокировка основного потока (main thread) долгими вычислениями. Благодаря Fiber, React может разделять работу на части, ставить её на паузу для обработки анимаций или ввода пользователя и возвращаться к ней позже, обеспечивая плавность интерфейса.

4.2. Опишите на высоком уровне, как Fiber организует работу рендера: что значит «разбить работу на части» и как это влияет на отзывчивость интерфейса?

Fiber организует работу как очередь мелких задач, превращая рекурсивный обход дерева в связный список.

  • Каждое обновление делится на «файберы» (атомарные юниты работы). React выполняет их по очереди, делая микро-паузы после каждого юнита.
  • В этих паузах React проверяет наличие высокоприоритетных событий (клик, ввод текста). Если они есть, он прерывает текущий рендер, обрабатывает действие пользователя и только потом возвращается к отрисовке.

4.3. Объясните различие между фазами render (reconciliation) и commit в React с точки зрения Fiber: какие операции могут быть прерваны/возобновлены, а какие должны выполняться атомарно, и почему?

Различие между фазами заключается в прерываемости и работе с DOM:

  • Фаза Render (Reconciliation): Это построение дерева Fiber и вычисление разницы (diffing) «в черновике». Она прерываема, может ставиться на паузу и выполняться асинхронно, так как не производит видимых изменений.
  • Фаза Commit: Это физическое применение вычисленных изменений в реальный DOM. Она атомарна (непрерываема), чтобы пользователь не увидел промежуточное, «разорванное» состояние интерфейса.

5. React. VirtualDOM

5.1. Что такое Virtual DOM в React и зачем он нужен при обновлении интерфейса?

Virtual DOM — это легкая копия реального DOM в виде JavaScript-объектов.

Он нужен для минимизации тяжелых операций с браузерным DOM. Вместо того чтобы перерисовывать страницу при каждом мелком изменении, React сначала просчитывает изменения в памяти, а затем применяет только необходимые «патчи» к реальному интерфейсу.

5.2. Объясните, как React использует Reconciliation для сравнения предыдущего и нового дерева элементов и принятия решения, что обновлять в реальном DOM

При обновлении состояния React создает новое дерево Virtual DOM и сравнивает его с предыдущим (Diffing algorithm).

  • Сравнение типов: Если тип элемента изменился (например, <div> заменили на ), React уничтожает старое дерево и строит новое с нуля.
  • Сравнение атрибутов: Если тип тот же, React обновляет только изменившиеся атрибуты (например, className или style).
  • Рекурсия по детям: React одновременно обходит списки дочерних элементов обоих деревьев, чтобы найти отличия.

5.3. Какие факторы могут ухудшать производительность при Reconciliation (например, частые перерисовки, нестабильные ключи, изменение структуры дерева), и как вы бы устно объяснили, почему это происходит на уровне сравнения Virtual DOM?

  1. Нестабильные ключи (key)
    • Почему: Если использовать index или Math.random(), React теряет связь между старым и новым элементом. При простом сдвиге списка он решит, что все элементы изменились, и перерисует их заново вместо простой перестановки.
  2. Изменение структуры дерева
    • Почему: Если вы обернули компонент в новый <div>, алгоритм увидит смену типа на верхнем уровне, удалит всю ветку и создаст её заново, даже если внутри ничего не поменялось.
  3. Частые перерисовки (Re-renders)
    • Почему: Каждое обновление запускает цикл сверки. Даже если итоговый DOM не меняется, процессор тратит время на создание объектов Virtual DOM и их полное сравнение (Diffing).

5.4. Объясните, как Fiber позволяет прерывать и возобновлять работу (time slicing) и как при этом обеспечивается согласованность дерева: какую роль играют приоритеты/lanes и двойная буферизация (current vs workInProgress)

Fiber — позволяет прерывать/возобновлять рендеринг.

  • Time slicing: работа разбита на части, можно прервать для важных задач
  • Двойная буферизация: current (показывается) и workInProgress (строится)
  • Lanes: приоритеты определяют очередность выполнения

6. React. Functional components

6.1. Что такое функциональный компонент в React и какую задачу он решает в приложении?

Что это: Обычная JavaScript-функция, принимающая props и возвращающая JSX.

Задача: Описывать интерфейс как чистую декларативную проекцию данных без громоздкого синтаксиса классов.

6.2. Как в функциональном компоненте управлять состоянием и чем отличается подход со state в функциональных компонентах от классовых?

Как: Через хук useState.

Отличия:

  • Классы: Состояние — это один объект this.state, обновляется через setState (слияние).
  • Функции: Состояние может быть атомарным (несколько useState), обновляется функцией-сеттером (замена). Нет this, данные сохраняются между рендерами за счет замыканий React.

6.3. Какие типичные причины лишних перерисовок у функциональных компонентов и какие устные стратегии оптимизации производительности вы бы применили (например, мемоизация, стабильность ссылок, разделение компонентов)?

Причины:

  • Обновление родителя (рендер идет вниз по дереву).
  • Нестабильные ссылки: Создание новых объектов/функций внутри тела компонента при каждом рендере.

Стратегии оптимизации:

  • React.memo: Пропускает рендер, если props не изменились.
  • useCallback / useMemo: Сохраняют стабильную ссылку на функции и объекты, чтобы не «ломать» React.memo у дочерних компонентов.
  • Разделение (Composition): Вынос часто меняющегося состояния в отдельный мелкий компонент, чтобы не перерисовывать тяжелую ветку дерева.

7. React. Class components

7.1. Что такое классовый компонент в React и какие обязательные элементы у него есть (например, render, props)?

Что это: ES6-класс, наследуемый от React.Component.

Обязательные элементы:

  • Метод render() — возвращает JSX.
  • props — объект входных данных (доступен через this.props).

7.2. Как в классовом компоненте работает состояние: чем отличается this.state от props и как правильно инициировать и обновлять состояние, чтобы не нарушать принципы React?

  • Props: Неизменяемы (read-only), приходят извне.
  • State: Внутренние данные, изменяемы.
  • Инициализация: В constructor через this.state = { … }.
  • Обновление: Только через this.setState(). Прямая мутация (this.state.x = 1) запрещена, так как не вызывает рендер.

7.3. Объясните, как в классовых компонентах реализуется обработка ошибок через Error Boundaries: какие методы жизненного цикла участвуют, что именно они перехватывают и какие ограничения у такого подхода?

Как работают: Компоненты-классы, ловящие ошибки в дочернем дереве.

Методы:

  1. static getDerivedStateFromError(error) — обновляет state, чтобы показать запасной UI.
  2. componentDidCatch(error, info) — для логирования ошибки.

Что перехватывают: Ошибки при рендеринге, в методах жизненного цикла и конструкторах детей.

Ограничения: Не ловят ошибки в обработчиках событий, асинхронном коде (setTimeout), самом себе и при серверном рендеринге.

8. React. Props

8.1. Что такое props в React и для чего они используются при передаче данных от родительского компонента к дочернему?

Props (свойства) — это объект с данными, который передается от родительского компонента дочернему. Они используются для конфигурации потомка и передачи ему информации. Внутри дочернего компонента props доступны только для чтения (immutable).

8.2. В чём ключевое различие между props и state, и как это различие влияет на то, кто и когда может изменять данные в компоненте?

Props — это внешние данные, которыми управляет родитель; компонент-получатель не может их изменять.

State — это внутренние данные, которые компонент создает и меняет сам (useState).

Различие определяет логику обновлений: компонент сам решает, когда обновить свой state, но он полностью зависит от родителя в вопросе получения новых props. Изменение любого из них приводит к перерисовке.

8.3. Как организовать «обратный поток данных» от дочернего компонента к родительскому с помощью props, и какие типичные ошибки или ограничения при этом встречаются?

Организуется через callback-функции: родитель передает функцию через props, а дочерний компонент вызывает её, передавая данные в аргументах.

Ошибки и ограничения:

  • Prop Drilling: передача функции через цепочку компонентов, которым она не нужна.
  • Мутация: попытка изменить проп-функцию или объект напрямую.
  • Сложность отслеживания: в глубоких деревьях трудно понять, где именно зародилось событие изменения.

9. React. State

9.1. Что такое состояние (state) в React и чем оно отличается от props с точки зрения того, кто и как может его изменять?

State — это внутренние данные компонента, которыми он управляет сам.

  • Кто меняет: Только сам компонент через useState или setState.
  • Отличие: В отличие от props, которые приходят извне и неизменны для получателя, state инкапсулирован и может обновляться в ответ на действия пользователя или события.

9.2. Почему обновления состояния через setState могут быть асинхронными и как это влияет на ситуацию, когда вы делаете несколько обновлений состояния подряд?

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

  • Проблема: При нескольких обновлениях подряд (setCount(count + 1)) последующие могут использовать старое значение переменной.
  • Решение: Использовать функцию-обработчик: setCount(prev => prev + 1).

9.3. Объясните, как пакетирование (batching) обновлений состояния влияет на количество перерисовок и согласованность данных, и какие подходы вы бы выбрали, чтобы минимизировать лишние рендеры в большом приложении со сложным состоянием

Batching (пакетирование) объединяет несколько изменений состояния в одну перерисовку (render), что предотвращает «мерцание» интерфейса и экономит ресурсы.

Как минимизировать лишние рендеры:

  • React.memo: для предотвращения ререндера дочерних компонентов при неизменных пропсах.
  • useMemo / useCallback: для мемоизации тяжелых вычислений и ссылок на функции.
  • Локализация состояния: спуск state как можно ниже по дереву компонентов.
  • Zustand / Redux: для точечного извлечения данных без проброса через всё дерево.

10. React. Lifecycle methods

10.1. Какие основные этапы жизненного цикла у классового компонента React (монтирование, обновление, размонтирование) и какие методы обычно к ним относятся?

  • Монтирование (Mounting): создание и вставка в DOM.
    • Методы: constructor, static getDerivedStateFromProps, render, componentDidMount.
  • Обновление (Updating): изменение props или state.
    • Методы: static getDerivedStateFromProps, shouldComponentUpdate, render, getSnapshotBeforeUpdate, componentDidUpdate.
  • Размонтирование (Unmounting): удаление из DOM.
    • Метод: componentWillUnmount.

10.2. В каких случаях срабатывает componentDidUpdate, какие аргументы он получает и как их использовать, чтобы корректно реагировать на изменения props или state и не попасть в бесконечный цикл обновлений?

Срабатывает сразу после обновления (кроме первого рендера).

  • Аргументы: prevProps, prevState, snapshot (из getSnapshotBeforeUpdate).
  • Как использовать: Сравнивать текущие значения с предыдущими.
  • Бесконечный цикл: Чтобы его избежать, любой вызов this.setState обязан находиться внутри условного оператора, проверяющего изменение конкретных данных (например, if (this.props.id !== prevProps.id)).

10.3. Объясните назначение getSnapshotBeforeUpdate: когда он вызывается, что должен возвращать, как его результат попадает в componentDidUpdate и в каких практических сценариях это помогает (например, сохранение позиции прокрутки) без ухудшения производительности?

Вызывается в фазе «пред-коммита», когда изменения уже вычислены, но DOM еще не обновлен.

  • Возвращает: Любое значение (snapshot) или null.
  • Передача данных: Результат попадает в componentDidUpdate как третий аргумент.
  • Сценарий: Сохранение состояния DOM, которое изменится после рендера (например, позиция скролла в чате). Это позволяет в componentDidUpdate программно скорректировать прокрутку так, чтобы пользователь не потерял место при добавлении новых сообщений.

10.4. Зачем нужен shouldComponentUpdate, какие данные он получает и как его решение может повлиять на производительность и поведение компонента?

shouldComponentUpdate — жизненный цикл для оптимизации производительности.

Что получает:

  • nextProps — новые пропсы
  • nextState — новый стейт

Как влияет:

  • Возвращает true → компонент перерисуется
  • Возвращает false → рендер и componentDidUpdate пропустятся

Зачем: предотвращает лишние рендеры, когда данные не изменились, ускоряя работу приложения.

11. React. Why hooks?

11.1. Почему в React появились хуки и какие проблемы классовых компонентов они помогают решить?

Хуки решают три ключевые проблемы классов:

  • Переиспользование логики: позволяют выделять состояние в кастомные хуки без «ада дескрипторов» (HOC, Render Props).
  • Раздутые компоненты: позволяют группировать код по смыслу (например, подписка на событие), а не разносить его по методам жизненного цикла (componentDidMount / componentWillUnmount).
  • Сложность this: избавляют от путаницы с контекстом вызова и привязкой методов.

11.2. Объясните правила использования хуков (например, почему их нельзя вызывать в условиях или циклах) и к каким ошибкам это приводит

  • Только на верхнем уровне: нельзя вызывать внутри циклов, условий или вложенных функций.
  • Только в React-функциях: в функциональных компонентах или кастомных хуках.

Причина: React полагается на строгий порядок вызова хуков для связи состояния с конкретной переменной. Последствия: Нарушение порядка (из-за условия или цикла) приведет к тому, что React вернет данные не того хука, что вызовет баги или падение приложения с ошибкой “Rendered more/fewer hooks than during the previous render”.

11.3. В каких ситуациях useMemo и useCallback действительно улучшают производительность, а в каких могут навредить? Объясните, как вы бы это оценивали на практике

  • Когда полезны: Тяжелые вычисления (фильтрация больших массивов) или передача ссылок в компоненты, обернутые в React.memo, чтобы избежать их лишней перерисовки.
  • Когда вредны: Для простых операций (сложение чисел, создание обычных функций). Затраты на сравнение зависимостей и выделение памяти под кэш могут превысить выгоду от «оптимизации».
  • Оценка: Использовать React Profiler для замера времени рендера. Если время выполнения компонента невелико, а React.memo не используется, хуки лучше не внедрять.

12. React. useState/useReducer/useContext

12.1. Что такое хук useState в React и в каких случаях его обычно используют для управления состоянием компонента?

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

  • Когда использовать: Для хранения простых значений (примитивов), небольших объектов или независимых переменных, которые не требуют сложной логики пересчета при изменении.

12.2. Объясните, в чём ключевые различия между useState и useReducer и по каким признакам вы бы выбрали один из них для конкретной задачи

Ключевое различие — в масштабе и связности данных.

  • useState: Идеален для простых данных. Логика обновления находится прямо в обработчиках событий. Выбирайте его, если состояние состоит из 1–2 независимых полей.
  • useReducer: Подходит для сложного состояния (объекты с глубокой вложенностью) или когда следующее состояние зависит от предыдущего. Логика вынесена в отдельную функцию-редюсер. Выбирайте его, если нужно централизовать управление данными или если изменение одного поля должно влиять на остальные.

12.3. Как useContext может повлиять на производительность приложения: почему обновления контекста могут вызывать лишние перерисовки и какие стратегии вы бы предложили для их уменьшения?

Причина перерисовок: Когда значение (value) в Provider обновляется, React автоматически ререндерит все компоненты-потребители (через useContext), независимо от того, какую именно часть данных из контекста они используют.

Стратегии оптимизации:

  • Дробление (Splitting): Разделение одного большого контекста на несколько маленьких по зонам ответственности.
  • Мемоизация (useMemo): Передача в value объекта, обернутого в useMemo, чтобы ссылка на него не менялась при каждом рендере провайдера.
  • Разделение на “Данные” и “Действия”: Создание двух контекстов — один для стейта, другой для функций обновления (которые не меняются).
  • Использование React.memo: Обертывание дочерних компонентов, чтобы изменения в родителе не вызывали их автоматический ререндер, если их пропсы стабильны.

13. React. useEffect/useLayoutEffect

13.1. Что делает хук useEffect в функциональном компоненте React и в какие моменты он обычно выполняется?

useEffect предназначен для выполнения побочных эффектов (side effects): запросов к API, подписок или манипуляций с DOM.

Когда выполняется: После того как компонент был отрисован на экране (после завершения цикла рендеринга и этапа “paint”).

13.2. Объясните ключевые различия между useEffect и useLayoutEffect: когда они запускаются относительно отрисовки и покраски (paint) и как это влияет на пользовательский интерфейс?

Ключевое различие — в моменте запуска относительно отрисовки браузером.

  • useEffect: Запускается асинхронно после того, как браузер отрисовал изменения на экране. Не блокирует отрисовку.
  • useLayoutEffect: Запускается синхронно после того, как React применил изменения к DOM, но до того, как браузер успел их отрисовать (этап “paint”).

13.3. Представьте, что после рендера вам нужно измерить размеры DOM-элемента и сразу скорректировать раскладку, чтобы избежать «прыжка» интерфейса. Как вы решите задачу и почему выберете useLayoutEffect или useEffect? Какие риски для производительности и блокировки рендера при этом нужно учитывать?

Для этой задачи следует использовать useLayoutEffect.

  • Почему: Поскольку он выполняется до “покраски”, любые изменения состояния или DOM, сделанные внутри него, применятся в том же кадре. Это позволяет избежать визуального “скачка” (фликкера), который возник бы при использовании useEffect.
  • Риски: useLayoutEffect является блокирующим. Пока код внутри него не выполнится, браузер не сможет отрисовать интерфейс. Тяжелые вычисления внутри этого хука приведут к заметным задержкам и снижению производительности (падению FPS).

14. React. Custom hooks

14.1. Что такое пользовательский хук в React и какую проблему он решает по сравнению с копированием логики между компонентами?

Пользовательский хук — это обычная JavaScript-функция, название которой начинается с use, и которая может вызывать другие хуки.

Решаемая проблема: Позволяет извлекать и переиспользовать логику состояния (stateful logic) между компонентами без изменения их иерархии. Избавляет от дублирования кода и делает компоненты чище.

14.2. Какие «Правила хуков» нужно соблюдать при использовании пользовательских хуков, и почему нарушение этих правил приводит к ошибкам в работе React?

  • Только на верхнем уровне: Нельзя вызывать хуки внутри условий, циклов или вложенных функций.
  • Только в функциях React: Вызов допустим только в функциональных компонентах или других пользовательских хуках.

Почему это важно: React полагается на строгий порядок вызовов хуков при каждом рендере, чтобы правильно сопоставлять внутреннее состояние с конкретным вызовом. Нарушение порядка (например, из-за условия if) приведет к тому, что React вернет данные не того хука, что вызовет баги или падение приложения.

14.3. Как бы вы спроектировали сложный пользовательский хук, который объединяет несколько хуков и обращается к внешнему API: какие ответственности вы бы разделили (состояние, эффекты, отмена запросов, обработка ошибок, кеширование), и как обеспечить переиспользуемость и предсказуемость поведения?

Для обеспечения предсказуемости и чистоты следует разделить ответственности:

  • Состояние (State): Использовать useReducer для управления сложным статусом (idle, loading, success, error) и данными.
  • Эффекты (Effects): useEffect для запуска запроса при изменении параметров (URL, ID).
  • Отмена запросов: Обязательное использование AbortController в функции очистки (cleanup) эффекта для предотвращения утечек памяти и race conditions.
  • Обработка ошибок: Блок try/catch с записью сообщения об ошибке в стейт для отображения в UI.
  • Кеширование: Вынос кеша во внешний объект или использование контекста/библиотек (типа React Query), чтобы избежать лишних сетевых вызовов.
  • Интерфейс (API): Возвращать объект с данными, флагами состояния и функцией для ручного перезапуска (refetch).

15. React. Other hooks

15.1. Что такое useRef в React и чем он отличается от useState с точки зрения влияния на рендеры компонента?

useRef — это хук, возвращающий объект с изменяемым свойством .current, которое сохраняется между рендерами.

Главное отличие: В отличие от useState, изменение значения в useRef не вызывает рендер компонента. Он используется для прямого доступа к DOM или хранения переменных, которые не должны влиять на визуальное отображение.

15.2. В каких случаях useLayoutEffect предпочтительнее useEffect, и какие риски или побочные эффекты могут возникнуть при его неправильном использовании?

Предпочтительнее: Когда нужно внести изменения в DOM (измерить размеры, изменить положение) до того, как пользователь увидит интерфейс.

  • Преимущество: Предотвращает визуальное мерцание («прыжки» контента).
  • Риски: Он блокирует отрисовку браузером. Если код внутри выполняется долго, приложение будет казаться зависшим (снижение FPS). Не подходит для тяжелых вычислений или сетевых запросов.

15.3. Объясните, как и зачем использовать useImperativeHandle вместе с forwardRef: какие проблемы он решает при проектировании публичного API компонента и какие есть альтернативы?

Зачем: Позволяет родительскому компоненту вызывать методы внутри дочернего через ref. forwardRef передает ссылку вниз, а useImperativeHandle ограничивает то, что будет доступно родителю.

Проблемы: Скрывает внутреннюю реализацию и предоставляет только контролируемое API (например, методы .focus() или .scrollIntoView()), предотвращая прямой и бесконтрольный доступ к узлам DOM.

Альтернативы:

  • Поднятие состояния (Lifting state up): Управление поведением через пропсы (рекомендуемый путь).
  • callback-refs: Передача функции из родителя в дочерний компонент для получения ссылки на элемент.
This post is licensed under CC BY 4.0 by the author.