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

год назад·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 компонентами?

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

Что такое JSX в React

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

Новички в React, вероятно, путаются в том, почему мы пишем HTML внутри JavaScript.

React без JSX

Давайте напишем React код без использования JSX, чтобы мы могли лучше знать, почему мы используем JSX в React.
let h1 = React.createElement('h1',{style:{color:"green"}}," h1 element");
let p = React.createElement('p',{style:{color:"red"}},"p element");
let div = React.createElement('div',{className:"container"},h1,p);

ReactDOM.render(div,document.querySelector('#app'))
React.createElement(type,props,children) принимает три аргумента. type: Это означает тип HTML-элемента, который нам нужен. (Пример: h1, h2, p, div и т.д.) props: Любые пропсы, необходимые для этого элемента. children: Данные, которые нам нужно добавить внутрь элемента html (пример: обычный текст или дочерние элементы)

React с JSX

Теперь заменим приведенный выше код на код с JSX.
let  green = {color:"green"};
let red = {color:"red"};

let h1 = <h1 style ={green}>h1 element</h1>;
let p = <p style={red}>p element</p>;
let div = <div className="container">{h1}{p}</div>

ReactDOM.render(div,document.querySelector('#app'))
JSX, который мы пишем внутри React, часто преобразуется в JavaScript с помощью транспилятора babel.

Что такое JSX?

JSX позволяет нам писать HTML-синтаксис внутри JavaScript. Используя JSX, мы можем сделать наш код более читабельным. JSX используется не только в React, но и в некоторых других фреймворках.

Выражения в JSX

В JSX мы можем встраивать выражения JavaScript, обернув фигурными скобками { }.
let h1 = <h1> Odd number {2+3}</h1>
let users = ['user1', 'user2', 'user3']

let ul = (
  <ul>
    {users.map((user,i)=>(
      <li>{user}</li>
    ))}
  </ul>
)
В приведенном выше коде мы использовали метод map для перебора массива и создали три элемента li.

Атрибуты в JSX

Встроенные (инлайновые) стили

// объект
let greenColor = {color: "green"}

let h1 = <h1 style={greenColor}>This is heading</h1>
Для встроенного стиля нам нужно передать свойства стиля как объект внутри фигурных скобок, так как объект является выражением JavaScript. Мы также можем передать объект стиля непосредственно в фигурные скобки вместо использования дополнительной переменной.
let h1 = <h1 style={{color:"green"}}>This is heading</h1>

Внешние стили, использующие classNames

Нам нужно использовать className вместо обычного атрибута class, который мы используем в HTML, потому что внутри JavaScript уже присутствует ключевое слово class.
let h1 = <h1 className="header-h1">This is heading</h1>

Компоненты React

Компонент представляет собой многократно используемый фрагмент кода в React, который возвращает React элемент.
function Button(props){
    return <button>{props.name}</button>
}

Условные выражения в JSX

function ShowHide(props) {
  if(props.show) {
    return <button>Show</button>
  } else {
    return <button>Hide</button>
  }
}

ReactDOM.render(<ShowHide show="true" />,document.querySelector('#app'))
Мы можем упростить приведенный выше код, используя тернарный оператор.
function ShowHide(props){
  return <button>{props.show ? "Show" : "Hide"}</button>
}

Оператор spread в JSX

Предположим, нам нужно передать данные компоненту User с помощью пропсов.
function User(props) {
  return (
    <div>
      <h1>{props.name}</h1>
      <ul>
        <li>{props.email}</li>
        <li>{props.mobile }</li>
      </ul>
    </div>
  )
}

<User name="John" email="user@example.com" mobile={11233} />
Передадим те же пропсы с помощью оператора spread.
let user = {
  name: "John",
  email: "user@example.com",
  mobile: 11233
}

<User {...user} />