Вопросы по React на собеседовании

2 года назад·3 мин. на чтение

В‌ ‌этой ‌статье рассмотрим вопросы, которые могут встретиться на собеседовании по ReactJS на позицию React или frontend разработчика в 2023 году.

Что нового появилось в React 18?

1. Автоматический батчинг setState

В React 17 только React события будут обрабатываться пакетно, а нативные JavaScript события, промисы, setTimeout и setInterval обрабатываться не будут. В React 18 все события обрабатываются пакетно, т.е. несколько setState будут объединены в одно выполнение, что повышает производительность. На уровне данных несколько обновлений состояния объединяются в одну обработку (на уровне представления несколько визуализаций объединяются в одну визуализацию).

2. Новый root API

В React 18 представлен новый root API, который поддерживает новый конкурентный рендеринг.
// React 17
import React from "react"
import ReactDOM from "react-dom"
import App from "./App"

const root = document.getElementById("root")
ReactDOM.render(root, <App />)

// unmount the component
ReactDOM.unmountComponentAtNode(root) 

// React 18
import React from "react"
import ReactDOM from "react-dom/client"
import App from "./App"

const root =  document.getElementById("root")
ReactDOM.createRoot(root).render(<App />)

// unmount the component
root.unmount()

3. Прекращение поддержки IE

Удалена поддержка браузера IE. Все новые функции, представленные React 18, основаны на современных браузерах. Если вам нужна поддержка IE, вам нужно вернуться к версии React 17.

4. flushSync

Используется, чтобы заставить React сбросить всю ожидающую работу и синхронно обновить DOM.
import React, {useState} from "react"
import {flushSync} from "react-dom"

const  App = () => {
  const [count, setCount] = useState(0)
  const [count2, setCount2] = useState(0)

  return (
    <div className="App">
      <button onClick={() => {
        // первое обновление
        flushSync(() => {
          setCount(count => count + 1)
        })
        // второе обновление
        flushSync(() => {
          setCount2(count2 => count2 + 1)
        })
      }}>click</ button >
       
      <span>count: {count}</ span >
      <span>count2: {count2}</ span >	
     </div>	
  )
}

export default App

5. Возвращаемое значение React компонента

В React 17 для возврата пустого компонента можно использовать только null, а явное возвращение undefined вызовет ошибку. В React 18 поддерживается возврат null и undefined.

6. Поддержка useId

Генерирует один и тот же уникальный идентификатор на сервере и клиенте, чтобы избежать несовместимости при гидратации.

7. Concurrent mode (Конкурентный режим)

Конкурентный режим — это не фича, а архитектура. Это помогает приложениям оставаться отзывчивыми, подстраиваясь под производительность устройства пользователя и скорость сети, а также устраняет блокировку механизмов рендеринга, делая рендеринг прерываемым. В React несколько состояний могут быть обновлены одновременно. Разница в том, чтобы синхронные непрерываемые обновления стали асинхронными прерываемыми обновлениями. useDeferredValue и startTransition используются для обозначения несрочного обновления.

Почему React компоненты не могут возвращать несколько элементов?

Почему компоненты React могут иметь только один корневой элемент?
  1. Компонент React в конце будет скомпилирован в функцию рендеринга, и возвращаемое значение функции может быть только одно. Если он не обернут в отдельный корневой узел, несколько значений будут возвращаться параллельно, что не допускается в JavaScript.
class App extends React.Component{
  render() {
    return(
      <div>
        <h1 className="title">Hello</h1>
        <span>World</span>	
      </div>	
    )
}

// После компиляции
class App extends React.Component {
  render() {
    return React.createElement('div', null,
      [
        React.createElement('h1', {className:'title'}, 'Hello'),
        React.createElement('span', null, 'World')
      ]
    )
  }
}
  1. Виртуальный DOM React представляет собой древовидную структуру, и корневой узел дерева может быть только один. При наличии нескольких корневых узлов невозможно подтвердить, какое дерево нужно обновить.

Как компоненты React могут возвращать несколько компонентов?

  • Используя HOC (Higher Order Functions)
  • Используя React.Fragment, вы можете добавить список элементов в группу, не создавая дополнительных узлов.
renderList() {
  list.map((item, key) => {
    return (
      <React.Fragment>
        <tr key={item.id}>
          <td>{item.name}</td>
          <td>{item.age}</td>
          <td>{item.address}</td>
        </tr>	
      </React.Fragment>
    )
  })
}
  • Используя массив
renderList(){
  list.map((item, key) => {
    return [
      <tr key={item.id}>
        <td>{item.name}</td>
        <td>{item.age}</td>
        <td>{item.address}</td>
      </tr>
    ]
  })
}

Каковы способы общения между React компонентами?

Существует множество способов взаимодействия компонентов, которые можно разделить на следующие категории:
  • Взаимодействие родительского компонента с дочерним компонентом
  • Дочерний компонент взаимодействует с родительским компонентом
  • Общение между соседними элементами
  • Родительский компонент взаимодействует с дочерними компонентами
  • Связь независимых компонентов
Подробнее о каждой категории можно прочитать в этой статье.
Также по теме собеседований рекомендую прочитать:

Что такое npm workspaces?

2 года назад·2 мин. на чтение

Набор функций в npm cli, с помощью которого можно управлять несколькими пакетами из единого корня проекта.

Workspaces (рабочие области) — это набору функций в npm cli, с помощью которого можно управлять несколькими пакетами из единого корневого пакета верхнего уровня. Этот функционал появился с 7й версии. Workspaces упрощают работу с монорепозиториями. Монорепозиторий - это способ организации проекта в котором множество подпроектов хранится в одном и том же репозитории. Workspaces упрощает работу со связанными пакетами. В нем автоматизирован процесс связывания (linking) и нет необходимости вручную использовать npm link для добавления ссылок на пакеты, которые должны быть связаны символическими ссылками в текущую папку node_modules. Каждый отдельный workspaces - это отдельный изолированный модуль, пакет или подпроект.

Создание проекта и workspace’ов

Проинициализируем проект, запустив npm init. Далее добавим в package.json поле workspaces. В это поле добавляем имена workspace'ов. packages/ обозначает, что мы поместим подпроекты в папку packages.
"workspaces": [
  "packages/components",
  "packages/app"
]
Создадим папки packages/components и packages/app и запустим npm init в каждой из них. Получаем такую структуру:
packages/
  app/
    package.json
  components/
    package.json
package.json
Запустим npm install. После запуска npm install папки packages/components и packages/app будут связаны символическими ссылками с node_modules. В результате структура папок будет выглядеть следующим образом:
packages/
  app/
      package.json
  components/
    package.json
node_modules/     // добавилось
  app/            // symlink на ../packages/app
  components/     // symlink на ../packages/components
package.json
package-lock.json // добавилось

Автоматическое создание нового workspace

Для того чтобы не создавать папки самим, можно запустить готовую команду. Добавим еще один подпроект с названием api.
npm init -w ./packages/api
Эта команда автоматически:
  • создаст папку api с package.json внутри;
  • добавит новый workspace в конфигурацию корневого package.json;
  • создаст symlink.

Добавление зависимостей в workspace

Для того чтобы добавить зависимость в определенный workspace нужно указать этот workspace в команде npm install :
npm install lodash -w components
Подобным образом можно запускать команды uninstall, ci и т.д.

Как ссылаться на workspace и использовать его

Воспользуемся функцией из одного workspace’а в другом. Создадим небольшую функцию в пакете components:
// packages/components/index.js

module.exports = {
  toUpperCase: (str) => String(str).toUpperCase()
}
Вызовем эту функцию в пакете app:
// packages/app/index.js

const { toUpperCase } = require('components')

console.log(toUpperCase('hello, world!')) // => 'HELLO, WORLD!'
Запустим скрипт:
node ./packages/app/index.js

Запуск команд в контексте workspace’а

Можно использовать параметр workspace для запуска команд в контексте выбранного пакета. Кроме того, если текущий каталог находится внутри workspace’а, конфигурация workspace’а задается неявно, а префикс устанавливается для корневого workspace’а. Из корня проекта запустим команду start для workspace’а app.
npm run start --workspace=app
Внутри workspace’а можно запустить команду обычном образом.
cd packages/app
npm run start
Аргумент --workspace можно указать несколько раз для запуска команды для нескольких workspace’ов:
npm run start --workspace=app --workspace=api
Для запуска команды в контексте всех workspace’ов нужно указать флаг --workspaces. Эта команда запустит команду start для каждого workspace’а в порядке указанном в поле workspaces в package.json.
npm run start --workspaces
Однако, может оказаться, что не во всех workspace’ах будет определен вызываемый скрипт. Чтобы избежать ошибок npm ERR! Error: Missing script: "start", нужно указать флаг --if-present. В этом случае npm пропустит workspace’ы, в которых вызываемый скрипт не определен.
npm run start --workspaces --if-present
Исходный код