Что такое ключ и преимущества его использования в списках?

«Ключ» — это специальный атрибут в React, который помогает однозначно идентифицировать каждый элемент в списке. При рендеринге динамических списков в React использование key prop для каждого элемента помогает React эффективно обновлять и повторно отображать элементы списка при внесении изменений. Свойство ключа должно быть стабильным идентификатором, таким как идентификатор или уникальное значение, связанное с каждым элементом в списке.

Пример кода:

const ListItem = ({ item }) => {
  return <li>{item.name}</li>;
};

const MyComponent = () => {
  const items = [
    { id: 1, name: 'Item 1' },
    { id: 2, name: 'Item 2' },
    { id: 3, name: 'Item 3' },
  ];

  return (
    <ul>
      {items.map((item) => (
        <ListItem key={item.id} item={item} />
      ))}
    </ul>
  );
};

Почему React использует className вместо атрибута класса?

React использует атрибут className вместо class для применения классов CSS к элементам, поскольку class является зарезервированным ключевым словом в JavaScript. Поскольку компоненты React написаны на JavaScript, использование class для применения классов CSS может привести к конфликтам с компонентами на основе классов. Чтобы избежать этих конфликтов, React использует className для определения классов CSS.

Пример кода:

const MyComponent = () => {
  return <div className="my-class">Hello, React!</div>;
};

Что такое опорное бурение и как его избежать?

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

Чтобы избежать детализации свойств, вы можете использовать React Context API или Redux для централизованного управления состоянием и предоставления компонентам доступа к необходимым данным без явной передачи их через свойства на каждом уровне.

В чем разница между useRef и createRef?

useRef и createRef используются для получения ссылок на элементы DOM или компоненты React, но они различаются по тому, как они используются.

createRef: Он используется в компонентах класса и создает новый объект ref каждый раз, когда компонент отображается. Требуется ручное управление для обновления значения ссылки.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }

  render() {
    return <div ref={this.myRef}>Hello, React!</div>;
  }
}

useRef: Используется в функциональных компонентах с React Hooks. В отличие от createRef, useRef сохраняет свое значение при рендеринге, что делает его подходящим для различных вариантов использования, таких как сохранение предыдущего состояния, доступ к последнему значению переменной и т. д.

const MyComponent = () => {
  const myRef = React.useRef();

  return <div ref={myRef}>Hello, React!</div>;
};

Что такое строгий режим в React?

StrictMode — это компонент более высокого порядка в React, который используется во время разработки для выявления потенциальных проблем в кодовой базе приложения. Это помогает выявлять и предупреждать о небезопасных методах, устаревших методах и потенциальных проблемах с производительностью.

import React from 'react';

const App = () => {
  return (
    <React.StrictMode>
      {/* Your application components */}
    </React.StrictMode>
  );
};

Почему методы класса должны быть привязаны к экземпляру класса?

В компонентах класса методы класса не привязываются автоматически к экземпляру компонента. Если вы напрямую используете метод класса без его привязки, контекст метода (т. е. this) будет неопределенным, что приведет к ошибкам.

Чтобы методы класса могли получить доступ к правильному контексту this, они должны быть явно привязаны к экземпляру класса. Обычно это делается в конструкторе класса или с помощью свойств класса со стрелочными функциями.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
    // Binding the class method to the instance
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    // Accessing this.state.count correctly here
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return <button onClick={this.handleClick}>Click Me</button>;
  }
}

Что делают эти три точки (…) в React?

В React три точки (...) являются частью синтаксиса распространения JavaScript и используются для распространения элементов массива или свойств объекта. Синтаксис расширения позволяет нам создавать новые массивы или объекты, включая свойства существующего массива или объекта.

Пример кода (распространение в массивах):

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const mergedArray = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]

Пример кода (распространение в объектах):

const obj1 = { x: 1, y: 2 };
const obj2 = { z: 3 };
const mergedObject = { ...obj1, ...obj2 }; // { x: 1, y: 2, z: 3 }

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

Что не так с использованием Context в React?

Использование Context в React по своей сути не является неправильным; на самом деле, это мощная функция для совместного использования состояния между компонентами без необходимости сверления пропеллеров. Однако есть некоторые соображения:

  • Чрезмерное использование контекста. Если вы чрезмерно используете контекст для всех потребностей управления состоянием, это может привести к запутанной и сложной в управлении структуре приложения. Контекст больше подходит для глобальных состояний, которые используются во всем приложении, а не для небольших локальных состояний.
  • Удобочитаемость: когда компоненты потребляют данные из контекста напрямую, это может сделать дерево компонентов менее читаемым, поскольку вы теряете видимость того, откуда поступают данные.
  • Тестирование. Тестирование компонентов, сильно зависящих от контекста, может стать более сложным, поскольку во время тестирования необходимо указать правильные значения контекста.
  • Redux против контекста: для более крупных приложений со сложными потребностями в управлении состоянием может быть более подходящим использование специальной библиотеки управления состоянием, такой как Redux.

Что такое композиция компонентов в React?

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

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

Пример кода:

const Header = () => <header>This is the header</header>;
const Sidebar = () => <aside>This is the sidebar</aside>;
const Content = () => <main>This is the main content</main>;
const Footer = () => <footer>This is the footer</footer>;

const App = () => (
  <div>
    <Header />
    <Sidebar />
    <Content />
    <Footer />
  </div>
);

Что означает пакетная обработка в ReactJS?

Пакетная обработка в ReactJS — это процесс объединения нескольких последовательных обновлений состояния в одно обновление для повышения производительности. React пакетно обновляет состояние по умолчанию, а это означает, что если вы вызываете setState несколько раз в одном и том же контексте выполнения (например, обработчике событий), React объединит эти обновления в пакет и выполнит один повторный рендеринг.

Пакетная обработка гарантирует, что React выполняет только одно обновление виртуального DOM, а затем согласовывает его с реальным DOM, уменьшая количество операций DOM и повышая общую производительность приложения.

Каковы преимущества пакетной обработки в ReactJS?

Пакетирование имеет ряд преимуществ:

  • Производительность: объединяя несколько обновлений в один повторный рендеринг, React сокращает количество операций DOM, делая приложение быстрее и эффективнее.
  • Избегайте избыточных рендеров: пакетная обработка гарантирует, что React обновит виртуальный DOM только один раз, даже если будет сделано несколько вызовов setState, что помогает избежать ненужных рендеров.
  • Непротиворечивость. Пакетная обработка гарантирует, что все обновления в одном контексте выполнения применяются вместе, что приводит к более согласованному состоянию рендеринга.

Какие методы жизненного цикла компонента класса заменены на useEffect в функциональном компоненте?

Хук useEffect в функциональных компонентах используется для обработки побочных эффектов и заменяет несколько методов жизненного цикла в компонентах класса:

  • componentDidMount: хук useEffect с пустым массивом зависимостей ([]) эквивалентен componentDidMount. Эффект запускается только один раз, после монтирования компонента.
  • componentDidUpdate: Хук useEffect без каких-либо зависимостей эквивалентен componentDidUpdate. Он запускает эффект после каждого рендера.
  • componentWillUnmount: Функция очистки, возвращаемая хуком useEffect, эквивалентна componentWillUnmount. Он запускается, когда компонент размонтирован.
import React, { useEffect } from 'react';

const MyComponent = () => {
  useEffect(() => {
    // This will run after the component is mounted (componentDidMount)
    return () => {
      // This will run when the component is unmounted (componentWillUnmount)
    };
  }, []); // Empty dependency array for componentDidMount
  // Or
  useEffect(() => {
    // This will run after every render (componentDidUpdate)
  }); // No dependency array for componentDidUpdate
  // ...
};

Сравните реализации useState и useReducer

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

useState: Это простой хук управления состоянием для управления состоянием локального компонента. Он возвращает переменную состояния и функцию для обновления этого состояния.

import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};

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

import React, { useReducer } from 'react';

const reducer = (state, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    default:
      return state;
  }
};

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  const increment = () => {
    dispatch({ type: 'INCREMENT' });
  };

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};

В простых случаях, когда логика управления состоянием проста, useState достаточно. Для более сложных сценариев управления состоянием лучше выбрать useReducer.

Покрывают ли React Hooks все варианты использования компонентов класса?

React Hooks охватывают большинство вариантов использования компонентов класса. С введением хуков функциональные компоненты получили возможность управлять состоянием, обрабатывать побочные эффекты и работать с контекстом, что ранее было возможно только с классовыми компонентами. Таким образом, для многих сценариев хуки обеспечивают более чистый и лаконичный способ написания компонентов.

Однако все еще могут быть некоторые крайние случаи или конкретные варианты использования, когда компоненты класса могут быть предпочтительными или необходимыми. Например, некоторые сторонние библиотеки или устаревшие кодовые базы могут сильно зависеть от компонентов класса. Но для большинства современных приложений React хуки должны покрывать необходимую функциональность.

Как я могу использовать границы ошибок в функциональных компонентах React?

Границы ошибок — это компоненты в React, которые перехватывают ошибки в дочернем дереве компонентов во время рендеринга, методов жизненного цикла или во время метода componentDidCatch. Границы ошибок полезны для изящной обработки ошибок и отображения резервного пользовательского интерфейса для пользователей, предотвращая сбой всего приложения из-за одной ошибки.

В функциональных компонентах вы можете использовать пользовательский хук useErrorBoundary, чтобы легко создать границу ошибки:

import React, { useState } from 'react';

const ErrorFallback = () => <div>Oops! Something went wrong.</div>;

const useErrorBoundary = () => {
  const [hasError, setHasError] = useState(false);

  const errorHandler = (error, errorInfo) => {
    console.error(error, errorInfo);
    setHasError(true);
  };

  if (hasError) {
    return <ErrorFallback />;
  }

  return { errorHandler };
};

const MyComponent = () => {
  const { errorHandler } = useErrorBoundary();

  // Wrap the code that might throw an error with try-catch
  try {
    // Your component code that might throw an error
    // ...
  } catch (error) {
    errorHandler(error, errorInfo);
  }

  return <div>Your component content</div>;
};

Когда бы вы использовали useRef?

Хук useRef в React используется для создания изменяемых ссылок на элементы или значения, которые сохраняются при рендеринге. Это полезно в сценариях, когда вам нужно получить доступ и изменить значение или элемент напрямую, не запуская повторную визуализацию компонента.

Вот некоторые распространенные варианты использования useRef:

  • Получение ссылок на элементы DOM: вы можете использовать useRef для прямого доступа к элементам DOM и управления ими, например, для установки фокуса или измерения размеров элемента.
  • Сохранение предыдущих значений: поскольку useRef сохраняет свое значение при рендеринге, вы можете использовать его для сохранения предыдущего состояния или значений реквизита и сравнивать их с текущими значениями.
  • Кэширование дорогостоящих вычислений: если у вас есть дорогостоящие вычисления, которые не нужно пересчитывать при каждом рендеринге, вы можете использовать useRef для сохранения вычисленного значения и прямого доступа к нему.
import React, { useRef, useEffect } from 'react';

const MyComponent = () => {
  const inputRef = useRef(null);

  useEffect(() => {
    // Focus the input element on mount
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} />;
};

Как бы вы передавали данные от дочернего к родительскому компоненту в React?

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

Пример кода:

// Parent component
const ParentComponent = () => {
  const handleChildData = (data) => {
    console.log('Received data from child:', data);
  };

  return <ChildComponent sendDataToParent={handleChildData} />;
};

// Child component
const ChildComponent = ({ sendDataToParent }) => {
  const handleClick = () => {
    const data = 'Hello from child!';
    sendDataToParent(data);
  };

  return <button onClick={handleClick}>Send Data to Parent</button>;
};

Какова цель супер (реквизита)?

В компонентах класса super(props) используется в конструкторе для вызова конструктора родительского класса (т. е. React.Component) и передачи ему props. Это необходимо, потому что в подклассе вы не можете получить доступ к this до вызова super().

Если вы хотите получить доступ к объекту props в конструкторе компонента класса, вам нужно вызвать super(props) для инициализации родительского класса и сделать props доступным для использования.

Пример кода:

class MyComponent extends React.Component {
  constructor(props) {
    super(props); // Call the constructor of the parent class
    // Now, this.props is accessible within the constructor
  }

  render() {
    return <div>Hello, {this.props.name}!</div>;
  }
}

Примечание. С появлением функциональных компонентов и React Hooks super(props) больше не нужен. В функциональных компонентах вы можете напрямую обращаться к объекту props.

Объясните концепцию виртуального DOM в React.

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

Вот как это работает:

  1. Когда состояние компонента или реквизиты изменяются, React создает новое представление Virtual DOM компонента.
  2. Затем React сравнивает новый виртуальный DOM с предыдущим (используя процесс, называемый «согласованием»), чтобы выявить различия или изменения между двумя версиями.
  3. После выявления изменений React вычисляет наиболее эффективный способ обновления реального DOM, чтобы он соответствовал новому виртуальному DOM.
  4. Наконец, React выполняет необходимые минимальные изменения для обновления реального DOM, что приводит к более оптимизированному и производительному процессу обновления.

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

Опишите Flux против MVC?

Flux и MVC — это архитектурные шаблоны, используемые в веб-приложениях, и они различаются подходом к обработке потока данных и управлению состоянием.

MVC (модель-представление-контроллер):

  • MVC — это традиционный архитектурный шаблон, используемый во многих фреймворках и приложениях.
  • В MVC приложение разделено на три основных компонента:
  1. Модель: представляет данные и бизнес-логику приложения.
  2. Представление: представляет пользовательский интерфейс и то, как данные должны быть представлены пользователю.
  3. Контроллер: действует как посредник между моделью и представлением. Он обрабатывает пользовательский ввод, обновляет модель и уведомляет представление об изменениях.
  • Поток данных в MVC является двунаправленным. Представления могут напрямую взаимодействовать с Моделью, а Контроллер облегчает это взаимодействие.

Поток:

  • Flux — это архитектурный шаблон, представленный Facebook для создания клиентских веб-приложений, особенно приложений React.
  • Flux обеспечивает однонаправленный поток данных, что означает, что данные проходят в одном направлении по всему приложению.
  • Во Flux приложение разделено на четыре компонента:
  1. Представление: представляет пользовательский интерфейс и отслеживает действия пользователя.
  2. Действия: простые объекты, представляющие события или действия пользователя.
  3. Диспетчер: центральный концентратор, который получает действия и отправляет их в зарегистрированные обратные вызовы (магазины).
  4. Хранилища: содержат состояние приложения и бизнес-логику. Они прослушивают отправленные действия, соответствующим образом обновляют свое состояние и уведомляют представления об изменениях.
  • Поток данных в Flux является однонаправленным, и представления могут запрашивать изменения состояния только путем отправки действий. Хранилища обрабатывают эти действия и соответствующим образом обновляют состояние, что затем запускает обновления представлений.

Однонаправленный поток данных Flux упрощает анализ изменений состояния и упрощает отладку и обслуживание больших приложений. React’s Context и Redux — это реализации шаблона Flux, которые обычно используются в экосистеме React.