React Flashcards
Что такое JSX?
JSX (JavaScript XML) - это расширение языка JavaScript, которое позволяет использовать XML-подобный синтаксис в React-приложениях. JSX — синтаксический сахар для функции React.createElement(component, props, …children). React приложения преобразуют JSX-код в обычный JavaScript-код с помощью компилятора.
Этот JSX-код:return <Component />
…конвертируется в:return React.createElement(SomeComponent, {a: 42, b: "testing"}, "Text Here")
…и результатом будет объект:
{
type: SomeComponent,
props: {a: 42, b: "testing"},
children: ["Text Here"]
}
Хотя JSX похож на HTML, это не HTML.
Is it possible to use React without JSX?
Да, вместо JSX можно использовать обычный JavaScript, вызывая функции React напрямую. К примеру, создать элемент можно с помощью React.createElement
// с использованием JSX
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
// без использования JSX
function Greeting(props) {
return React.createElement('h1', null,
Hello, ${props.name}!);
What is the virtual DOM? How does react use the virtual DOM to render the UI?
Реальный DOM (Real DOM) - это модель документа, которая представляет собой структуру дерева элементов на странице. Использование DOM снижает производительность приложения, т.к. после изменения элемента и его дочерних элементов требуется перерисовка всего пользовательского интерфейса.
Виртуальный DOM представляет собой виртуальное представление DOM. Если изменяется состояние какого-то элемента, создается новое виртуальное дерево DOM. Затем это дерево сравнивается с предыдущим виртуальным деревом DOM. Этот процесс называется “diffing” (сравнение различий).
Когда React знает, какие объекты виртуального DOM изменились, он обновляет только эти объекты в реальном DOM. Это гарантирует минимальное количество операций в реальном DOM и снижает затраты на обновление реального DOM в производительностном отношении.
Являются ли виртуальный DOM и Shadow DOM одним и тем же?
Нет.
Виртуальный DOM – это концепция программирования, используемая для повышения производительности .
Shadow DOM - это технология браузера, разработанная для создания изолированных веб-компонентов с собственной структурой, стилями и поведением, чтобы избежать конфликтов с другими компонентами на странице.
Чем отличается виртуальный DOM от реального DOM?
- Реальный/абстрактный: Реальный DOM - представляет структуру HTML-элементов на странице. Виртуальный DOM - не привязан к реальному документу и существует только в памяти компьютера.
- Обновление: Реальный DOM обновляется непосредственно в браузере при изменении состояния элементов на странице, в то время как виртуальный DOM обновляется в памяти компьютера.
- Производительность: Реальный DOM может быть медленным и затратным в обработке большого количества элементов и обновлений, так как каждое изменение может привести к перестройке и перерисовке всего дерева элементов. Виртуальный DOM более эффективен, так как он позволяет сначала обновлять виртуальное дерево элементов, а затем только те части реального DOM, которые изменились.
- Изоляция: Реальный DOM не предоставляет изоляции для компонентов на странице. Виртуальный DOM предоставляет изоляцию для компонентов, которые могут быть переиспользованы в разных частях страницы без конфликтов.
When is a component rendered in React?
Процесс рендеринга в React запускается вызовом метода render() компонента. Этот метод возвращает описание того, как должен выглядеть компонент в виде дерева элементов React. Затем React использует это дерево и строит соответствующее дерево элементов DOM, которое добавляется в реальный DOM.
Когда состояние (state) или свойства (props) компонента изменяются, React автоматически перерендеривает компонент и обновляет DOM, чтобы отобразить изменения.
В React существуют методы жизненного цикла - специальные функции, которые вызываются в определенные моменты жизни компонента, к примеру, когда компонент создается, обновляется или удаляется. Эти методы позволяют разработчикам управлять процессом рендеринга, определять, когда компонент должен быть обновлен, или выполнить дополнительные действия после обновления компонента.
How not to render on props change?
Есть несколько способов избежать перерендеринга компонента при изменении его свойств (props)
1. Используйте shouldComponentUpdate()
— этот метод жизненного цикла позволяет вам контролировать, должен ли компонент повторно отображаться.
class MyComponent extends React.Component {
shouldComponentUpdate(nextProps) {
if (this.props.myProp === nextProps.myProp) {
return false;
}
return true;
}
render() {
// ...
}
}
- Используйте
PureComponent
. PureComponent — это базовый класс для компонентов, который автоматически реализует shouldComponentUpdate() с поверхностным сравнением свойств и состояний.
class MyComponent extends React.PureComponent {
render() {
// ...
}
}
- Используйте функцию высшего порядка
React.memo()
. React.memo() — это higher-ordercomponent (HOC), который можно использовать для обертывания функционального компонента. Он работает аналогично PureComponent.
Эта функция позволяет кэшировать результаты рендеринга компонента и перерендеривать его только тогда, когда изменяются его свойства.
Чтобы использовать React.memo(), нужно обернуть компонент в эту функцию. Например:
import React from 'react';
const MyComponent = React.memo(props => {
// Рендеринг компонента
});
export default MyComponent;
Оберните компонент в мемо, чтобы получить мемоизированную версию этого компонента. Эта запомненная версия вашего компонента обычно не будет повторно отображаться при повторном отображении его родительского компонента, если его реквизиты не изменились. Но React все еще может перерендерить его: мемоизация — это оптимизация производительности, а не гарантия.
Можно ли использовать стрелочные функции в методах рендеринга?
Вообще говоря, да, это нормально, и часто это самый простой способ передать параметры функциям обратного вызова.
function MyComponent() {
const handleClick = useCallback(() => {
console.log('Button clicked');
}, []);
return (
<div>
<button onClick={handleClick}>Click me</button>
</div>
);
}
Как передать значение от дочернего к родительскому компоненту?
Передайте callback функцию в качестве свойства дочернему компоненту, которую дочерний компонент может вызвать
// Родительский компонент
function ParentComponent() {
function handleLanguageSelect(language) {
console.log(Выбран язык ${language}
);
}
//
return (
<div>
<h1>Родительский компонент</h1>
<SelectLanguage onLanguageSelect={handleLanguageSelect} />
</div>
);
}
//
// Дочерний компонент
function SelectLanguage(props) {
function handleChange(event) {
const selectedLanguage = event.target.value;
props.onLanguageSelect(selectedLanguage);
}
//
return (
<div>
<label>Выберите язык:</label>
<select id=”language-select” onChange={handleChange}>
<option>Английский</option>
<option>Французский</option
</select>
</div>
);
}</option>
Также можно через createContext или через редакс.
Как передать значение от родительского к дочернему компоненту?
Передать значение через props, также, чтобы избежать prop drilling
, можно передавать через createContext
, или через редакс.
Контекст предоставляет способ передачи данных глубоко в дерево компонентов без необходимости передавать пропсы через каждый вложенный компонент.
// Создаем контекст
const MyContext = React.createContext();
//
// Родительский компонент, который предоставляет значение через контекст
function ParentComponent() {
const valueToPass = “Hello, child!”; // значение, которое мы хотим передать
//
return (
<div>
<h1>Родительский компонент</h1>
<MyContext.Provider value={valueToPass}>
<ChildComponent></ChildComponent>
</MyContext.Provider>
</div>
);
}
//
// Дочерний компонент, который получает значение из контекста
function ChildComponent() {
return (
<div>
<h2>Дочерний компонент</h2>
<MyContext.Consumer>
{value => <p>{value}</p>}
</MyContext.Consumer>
</div>
);
}
Redux - это библиотека для управления состоянием приложения, которая позволяет хранить данные в глобальном хранилище (store) и обновлять их через действия (actions).
Что такое “prop drilling”?
“Prop drilling” - это когда вы передаете свойства (props) от некоторого компонента FirstComponent к другому компоненту SecondComponent, которому на самом деле не нужны эти данные, и который только передает их дальше к компоненту ThirdComponent и, возможно, дальше по цепочке.
Может ли дочерний компонент изменять свои собственные свойства (props)?
Нет, не может. Он может менять state, но не может менять props.
Попытка изменения свойств может привести к ошибкам и нестабильному состоянию приложения.
Как передать значение от sibling к sibling?
Использовать “подъем состояния” (lifting state up) для передачи состояния из одного компонента в другой через родительский компонент.
Это позволяет обеспечить согласованность данных и упростить управление состоянием приложения.
function CounterWrapper() {
const [count, setCount] = useState(0);
//
const incrementCount = () => {
setCount(count + 1);
};
//
return (
<div>
<Counter count={count} />
<Button handleClick={incrementCount} />
</div>
);
}
//
function Counter({ count }) {
return (
<div>
<h1>{count}</h1>
</div>
);
}
//
function Button({ handleClick }) {
return (
<div>
<button onClick={handleClick}>Increment</button>
</div>
);
}
В чем разница между props и state?
Props - это в основном параметры, с которыми инициализируется дочерний компонент. Эти параметры передаются дочернему от родительского компонента и являются неизменными. State принадлежит самому компоненту и управляется им. Состояние всегда инициализируется значением по умолчанию, и это значение может изменяться в течение жизненного цикла компонента в ответ на события. Когда состояние изменяется, компонент перерисовывается.
Как состояние (state) в классовом компоненте отличается от состояния в функциональном компоненте?
Объект state применялся только в классах-компонентах, а в функциональных используются хуки.
При использовании класса-компонента единственное место, где можно установить объект state - это конструктор класса. Для обновления состояния вызывается функция setState()
.
class Hello extends React.Component {
constructor(props) {
super(props);
this.state = {welcome: “Добро пожаловать на сайт!”};
}
render() {
return <h1>{this.state.welcome}</h1>;
}
}
Изменение состояния вызовет повторный рендеринг компонента, в соответствии с чем веб-страница будет обновлена.
this.setState({welcome: "Привет React"});
В функциональном компоненте используется хук useState, который вызывается каждый раз при рендеринге компонента. Он инициализирует состояние и метод изменения этого состояния.
import React, { useState } from ‘react’;
//
function Counter() {
const [count, setCount] = useState(0);
//
const handleIncrement = () => {
setCount(count+ 1);
};
//
return (
<div>
<h1>Count: {count}</h1>
<button onClick={handleIncrement}>Increment</button>
</div>
);
}
//
export default Counter;
Что такое жизненный цикл компонента?
- Инициализация (Initialization):
-constructor()
: Метод конструктора компонента, в котором можно инициализировать состояние и привязывать методы к экземпляру компонента. Этот метод вызывается при создании компонента. - Монтирование (Mounting):
-componentDidMount()
: Метод вызывается сразу после рендеринга компонента в DOM. Используется для выполнения сайд-эффектов, таких как загрузка данных с сервера, установка подписок на события или взаимодействие с DOM элементами.
-static getDerivedStateFromProps()
: Метод вызывается как на этапе монтирования, так и на этапе обновления. Он используется для обновления состояния компонента на основе новых свойств (props
). Возвращает новое состояние на основе измененных свойств.
-render()
: Метод отрисовывает содержимое компонента и возвращает JSX элементы. - Обновление (Updating):
-shouldComponentUpdate()
: Метод вызывается при попытке обновить компонент. Он определяет, должен ли компонент обновиться и перерисоваться после изменения состояния или свойств. Используется для оптимизации производительности путем предотвращения ненужных перерисовок.
-componentDidUpdate()
: Метод вызывается после выполнения обновлений компонента в DOM. Используется для выполнения дополнительных сайд-эффектов, таких как выполнение запросов к API или обновление внешних библиотек.
-static getDerivedStateFromProps()
: Метод вызывается как на этапе монтирования, так и на этапе обновления. Он используется для обновления состояния компонента на основе новых свойств (props
). Возвращает новое состояние на основе измененных свойств.
-render()
: Метод обновляет отображение компонента.
-getSnapshotBeforeUpdate()
: Метод вызывается прямо перед применением обновлений к DOM. Он позволяет компоненту захватить текущее состояние DOM перед изменениями, такими как прокрутка или позиция фокуса. Возвращает значение, которое будет передано методуcomponentDidUpdate()
. - Размонтирование (Unmounting):
-componentWillUnmount()
: Метод вызывается перед удалением компонента из DOM. Используется для очистки ресурсов, отписки от событий или отмены таймеров.
Используя методы жизненного цикла классовых компонентов или hook useEffect в функциональных компонентах, мы можем запускать код в определенные моменты жизни компонента.
- Монтирование:
-useEffect(() => {}, [])
: Этот хук сработает только один раз после первого рендеринга компонента, аналогично методуcomponentDidMount
. Здесь можно инициализировать состояние, подписываться на события или выполнять другие сайд-эффекты. - Обновление:
-useEffect(() => {})
: Этот хук сработает после каждого рендеринга компонента, аналогично методуcomponentDidUpdate
. Здесь можно обрабатывать изменения состояния или свойств и выполнять соответствующие действия.
-useMemo(() => {}, [dependency])
: Этот хук служит для мемоизации значений и повышения производительности, аналогично использованиюshouldComponentUpdate
. Он вычисляет и возвращает значение только в том случае, если его зависимость изменилась. - Размонтирование:
-useEffect(() => { return () => {} }, [])
: Этот хук сработает перед размонтированием компонента, аналогично методуcomponentWillUnmount
. Здесь можно выполнять очистку ресурсов, отписку от событий или выполнение других необходимых действий перед удалением компонента из DOM.
Как обновить жизненный цикл в функциональных компонентах?
Используя hook useEffect.
useEffect принимает два аргумента: колбэк-функцию, которая содержит код побочного эффекта, и массив зависимостей. Колбэк-функция запускается после каждого рендеринга компонента. Если массив зависимостей передан, то эффект запускается только в том случае, если значения в массиве изменились с момента последнего запуска эффекта.
с помощью хука useEffect можно имитировать методы жизненного цикла componentDidMount, componentDidUpdate и componentWillUnmount.
// метод componentDidMount
useEffect(() => {
console.log('Component mounted');
}, []);
//
// метод componentDidUpdate
useEffect(() => {
console.log('Component updated');
}, [count]);
//
// метод componentWillUnmount
useEffect(() => {
return () => {
console.log('Component unmounted');
}
}, []);
Какова разница между refs и переменными состояния (state)?
И refs, и переменные состояния сохраняют значения между рендерами, но только переменные состояния вызывают повторный рендер компонента.
ref может быть использован для получения доступа к методам и свойствам компонента, которые не являются доступными через его props. Например, ref можно использовать для получения ссылки на поле ввода (<input></input>) и вызова метода focus() для установки фокуса на него.
Хук useRef позволяет сохранить некоторый объект, который можно изменять и который хранится в течение всей жизни компонента. В качестве параметра функция useRef() принимает начальное значение хранимого объекта. А возвращаемое значение - ссылка-объект, из свойства current которого можно получить хранимое значение.
const refUser = useRef("Tom");
console.log(refUser.current); // Tom
<input type="text" ref={ refUser } />
Когда лучше всего использовать refs?
Один из способов использования refs - это прямой доступ к элементу DOM для его манипулирования. Например, это может быть необходимо при интеграции с сторонней библиотекой DOM или для запуска императивных анимаций.
Второй способ использования refs - это функциональные компоненты, где они иногда являются хорошим выбором для сохранения значений между рендерами без вызова повторного рендера компонента при изменении значения.
Использовать refs советуют только при необходимости, чтобы избежать нарушения инкапсуляции.
Как правильно обновлять ref в функциональном компоненте?
С помощью hook useRef! А в классовых с помощью React.createRef().
Какова разница между API контекста и prop drilling? Когда не следует использовать API контекста?
Prop drilling - это процесс передачи данных от компонента к компоненту через пропсы. Если компонент A должен передать данные компоненту C, но компонент B находится между ними, то компонент A должен передать данные через пропсы компоненту B, а затем компонент B должен передать эти данные компоненту C через его пропсы. Этот процесс может стать громоздким и неудобочитаемым, особенно если компонентов много.
API контекста дает нам централизованное хранилище данных, к которому мы можем неявно обращаться, используя метод contextType или хук useContext, чтобы получать данные из любого компонента. Основным недостатком API контекста является то, что каждый раз, когда контекст меняется, все компоненты, потребляющие значение, перерисовываются. Это может иметь отрицательные последствия для производительности. По этой причине следует использовать API контекста только для редко обновляемых данных, таких как настройки темы.
Redux
Основная идея redux заключается в том, что все состояние приложения хранится в одном хранилище. Store (хранилище) - это просто JavaScript объект.
Единственный способ изменить состояние — отправить действие (action) из вашего приложения, а затем написать редьюсеры для этих действий, которые изменяют состояние.
Весь переход состояния хранится внутри редьюсеров и не должен иметь никаких побочных эффектов.
Основные принципы Redux включают единообразность состояния, неизменяемость состояния и предсказуемость изменений состояния.
Единообразность состояния означает, что состояние всего приложения хранится в одном месте - в store. Это позволяет упростить управление состоянием приложения и делает его более предсказуемым.
Неизменяемость состояния означает, что состояние не должно изменяться напрямую. Вместо этого, каждый раз при изменении состояния создается новый объект состояния. Это позволяет удобно отслеживать изменения состояния и уменьшает вероятность ошибок, связанных с изменением состояния напрямую. Все обновления состояния выполняются через действия (actions), которые передаются в store через dispatch и reducers.
Предсказуемость изменений состояния означает, что все изменения предсказуемы и могут быть отслеживаемыми. Это реализуется за счет редукторов – чистых функций. Таким образом, мы можем легко отследить, какие изменения произошли в состоянии в ответ на действия или внешние события.
import { createStore } from 'redux';
//
// Определяем начальное состояние
const initialState = {
counter: 0
};
//
// Определяем reducer
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, counter: state.counter + 1 };
case 'DECREMENT':
return { ...state, counter: state.counter - 1 };
default:
return state;
}
}
//
// Создаем store
const store = createStore(counterReducer);
//
function App() {
// Получаем текущее значение состояния
const counter = store.getState().counter;
//
// Диспатчим действия
const increment = () => store.dispatch({ type: 'INCREMENT' });
const// Диспатчим действия
const decrement = () => store.dispatch({ type: 'DECREMENT' });
//
return (
<div>
<h1>Counter: {counter}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}
В этом примере мы создаем начальное состояние, определяем reducer, который определяет, какие действия могут изменять состояние, и создаем store, который хранит состояние приложения. Затем мы создаем компонент App, который получает текущее значение состояния из store и диспатчит действия для изменения состояния.
Когда мы вызываем функцию increment или decrement, мы отправляем действие в store, которое вызывает reducer. Редьюсер изменяет состояние в соответствии с переданным действием, и store обновляет состояние приложения. Затем компонент App перерисовывается, чтобы отобразить новое значение состояния.
Каков типичный поток данных в приложении React + Redux?
- Начальная настройка:
* Store Redux создается с использованием функции корневого редуктора и сохраняет возвращаемое значение как начальное состояние (state)
const rootReducer = combineReducers({
counter: counterReducer,
todos: todoReducer
});
- Компоненты пользовательского интерфейса получают доступ к текущему состоянию хранилища Redux и используют эти данные, чтобы решить, что отображать. Они также подписываются на любые будущие обновления store, чтобы знать, изменилось ли состояние.
const count = useSelector(state => state.counter);
- Обновления:
* Что-то происходит в приложении, например, пользователь нажимает кнопку и код приложения отправляет действие в store Redux через dispatch, например
*
dispatch({type: ‘counter/incremented’})
- Store снова запускает функцию редуктора с предыдущим state и текущим action и сохраняет возвращаемое значение как новое state
- Store уведомляет все части пользовательского интерфейса, на которые оформлена подписка, об обновлении.
- Каждый компонент пользовательского интерфейса, которому нужны данные из хранилища, проверяет, не изменились ли нужные им части состояния.
- Каждый компонент, который видит, что его данные изменились, вызывает повторный рендер с новыми данными.
Технические преимущества использования Redux.
- Легкий перенос состояния между компонентами
- Предсказуемые состояния - если одно и то же состояние и действие передаются в редьюсер, то генерируется одинаковый результат, так как функции редьюсера являются чистыми. Это позволяет выполнять сложные задачи, такие как постоянное отмена и повторение действий. Доступны также временные путешествия, которые могут перемещаться вперед и назад между предыдущими состояниями, и результаты можно просматривать в режиме реального времени
- Может быть использован для рендеринга на стороне сервера. Просто передайте созданный на сервере store на сторону клиента.
- Большое количество инструментов разработчика
Это хорошая идея использовать Math.random для ключей?
Использование Math.random() для генерации ключей не является хорошей идеей, так как это может привести к возникновению коллизий и дубликатов ключей.
Вместо этого можно использовать данные из базы данных, UUID или другую библиотеку.
Каковы ограничения React?
React считается относительно тяжелой зависимостью и может быть избыточным для небольших приложений.
В React команды зависят от дополнительных библиотек для получения данных, таких как Axios или Fetch.
Что такое Higher Order Component, HOC?
Это функция, которая принимает компонент и возвращает новый модифицированный компонент.
Хотя HOC’ы ассоциируются с React, они не являются функцией React, а скорее являются паттерном, вдохновленным функциональным программированием, называемым функциями более высокого порядка.
Один из примеров HOC с открытым исходным кодом - это React Sortable HOC, при котором вы передаете компонент списка (на основе ul) и получаете улучшенный ul с возможностями сортировки и перетаскивания.
import React from "react";
//
// HOC, который добавляет стиль к компоненту
function withStyle(WrappedComponent, style) {
return function(props) {
return (
<div style={style}>
<WrappedComponent {...props} />
</div>
);
};
}
//
// Компонент, который мы будем оборачивать
function MyComponent(props) {
return <h1>Hello, {props.name}!</h1>;
}
//
// Оборачиваем MyComponent в HOC с заданным стилем
const StyledComponent = withStyle(MyComponent, { color: "red" });
//
// Используем оба компонента
function App() {
return (
<div>
<MyComponent name="Alice" />
<StyledComponent name="Bob" />
</div>
);
}
//
export default App;
Что такое Controlled and Uncontrolled Components?
В HTML элементы формы, такие как input, textarea и select, обычно сами управляют своим состоянием и обновляют его когда пользователь вводит данные. В React мутабельное состояние обычно содержится в свойстве компонентов state и обновляется только через вызов setState().
Управляемый компонент - это компонент ввода, такой как input, textarea или select, значение которого контролируется React.
Чтобы взять под контроль этот компонент в React, вам нужно подписаться на событие onChange у textarea и обновлять переменную состояния (например, называемую input) в ответ на это событие.
Теперь React управляет значением textarea, поэтому вам также нужно взять на себя ответственность за установку свойства value для textarea.
Неуправляемый компонент управляет своим собственным состоянием - компонент не контролируется React и, следовательно, является “неуправляемым”.
Представьте, что вы добавили на страницу textarea и начали печатать. Все, что вы печатаете, будет автоматически сохраняться в textarea и будет доступно через его свойство value. Хотя React может получить доступ к значению с помощью ref, но React не контролирует значение в этом случае. Это будет примером неуправляемого компонента. Неуправляемые компоненты опираются на DOM в качестве источника данных и могут быть удобны при интеграции React с кодом, не связанным с React. Количество кода может уменьшиться, правда, за счёт потери в его чистоте. Поэтому в обычных ситуациях мы рекомендуем использовать управляемые компоненты.
Оптимизация производительности для приложений React
- Используйте PureComponent или React.memo: PureComponent и React.memo предоставляют оптимизированную реализацию метода shouldComponentUpdate, что позволяет уменьшить количество лишних перерисовок компонентов.
- Используйте React.lazy()
Ленивая загрузка позволяет разбить приложение на небольшие фрагменты, которые загружаются по мере необходимости. Это помогает ускорить время загрузки и уменьшить объем передаваемых данных.
import React, { lazy, Suspense } from 'react';
//
const LazyComponent = lazy(() => import('./LazyComponent'));
//
function App() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
</div>
);
}
//
export default App;
- Using Production Mode Flag in Webpack
Если вы используете webpack 4 в качестве сборщика модулей для своего приложения, вы можете установить mode в режим производства, что говорит веб-пакету использовать встроенную оптимизацию:module.exports = { mode: 'production' };
- Используйте виртуализацию списка:
Виртуализация списка позволяет отображать только те элементы списка, которые видны на экране, а не все элементы сразу. Это может существенно ускорить время отрисовки больших списков.
import React from 'react';
import { FixedSizeList } from 'react-window';
//
function MyList(props) {
const { items } = props;
//
const Row = ({ index, style }) => (
<div style={style}>{items[index]}</div>
);
//
return (
<FixedSizeList
height={400}
itemCount={items.length}
itemSize={50}
width={300}
>
{Row}
</FixedSizeList>
);
}
//
export default MyList;
- Оптимизация зависимостей
При рассмотрении вопроса об оптимизации размера пакета приложения стоит проверить, сколько кода вы фактически используете из зависимостей. Например, вы можете использовать Moment.js, который включает локализованные файлы для многоязычной поддержки. Если вам не нужно поддерживать несколько языков, вы можете рассмотреть возможность использования плагина moment-locales-webpack-plugin, чтобы удалить неиспользуемые локали для вашего окончательного пакета. Другой пример — loadash. Допустим, вы используете только 20 из 100+ методов, тогда наличие всех дополнительных методов в окончательном пакете не является оптимальным. Так что для этого вы можете использовать lodash-webpack-plugin для удаления неиспользуемых функций. Вот обширный список зависимостей, которые вы можете оптимизировать. - Используйте React.Fragments, чтобы избежать дополнительных оболочек HTML-элементов
React.fragments позволяет группировать список дочерних элементов без добавления дополнительного узла.
class Comments extends React.PureComponent{
render() {
return (
<React.Fragment>
<h1>Comment Title</h1>
<p>comments</p>
<p>comment time</p>
</React.Fragment>
);
}
}
- Избегайте определения встроенной функции в функции рендеринга.
Когда вы определяете функцию внутри функции render, это приводит к созданию новой функции при каждом рендеринге компонента, что может привести к нежелательному расходу ресурсов и замедлению производительности.
default class CommentList extends React.Component {
state = {
comments: [],
selectedCommentId: null
}
//
render(){
const { comments } = this.state;
return (
comments.map((comment)=>{
return <Comment onClick={(e)=>{
this.setState({selectedCommentId:comment.commentId})
}} comment={comment} key={comment.id}/>
})
)
}
}
Вместо определения встроенной функции для реквизита вы можете определить функцию стрелки.
default class CommentList extends React.Component {
state = {
comments: [],
selectedCommentId: null
}
//
onCommentClick = (commentId)=>{
this.setState({selectedCommentId:commentId})
}
//
render(){
const { comments } = this.state;
return (
comments.map((comment)=>{
return <Comment onClick={this.onCommentClick}
comment={comment} key={comment.id}/>
})
)
}
}
- Избегайте использования индекса в качестве key
Так как это может вызвать проблемы, к примеру, при удалении элемента. - Memoize React Components
Мемоизация — это метод оптимизации, используемый в основном для ускорения работы компьютерных программ за счет сохранения результатов дорогостоящих вызовов функций и возврата кэшированного результата при повторении тех же входных данных. Запоминаемая функция обычно быстрее, потому что если функция вызывается с теми же значениями, что и предыдущая, то вместо выполнения логики функции она будет извлекать результат из кеша.
const UserDetails = ({user, onEdit}) => {
const {title, full_name, profile_img} = user;
//
return (
<div className="user-detail-wrapper">
<img src={profile_img} />
<h4>{full_name}</h4>
<p>{title}</p>
</div>
)
}
Здесь все дочерние элементы в UserDetails основаны на свойствах. Этот компонент без сохранения состояния будет перерисовываться при изменении свойства. Если маловероятно, что атрибут компонента UserDetails изменится, то он является хорошим кандидатом на использование memoize-версии компонента:
const UserDetails = ({user, onEdit}) =>{
const {title, full_name, profile_img} = user;
//
return (
<div className="user-detail-wrapper">
<img src={profile_img} />
<h4>{full_name}</h4>
<p>{title}</p>
</div>
)
}
//
export default React.memo(UserDetails)
Перечислить встроенные хуки React рассказать о каждом подробнее
- useState:
Хук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> ); };
- useEffect:
ХукuseEffect
позволяет выполнять побочные эффекты в функциональных компонентах, также используется как аналог методов жизненного цикла для функциональных компонентов. Пример:import React, { useState, useEffect } from 'react'; // const Timer = () => { const [seconds, setSeconds] = useState(0); // useEffect(() => { const intervalId = setInterval(() => { setSeconds((prevSeconds) => prevSeconds + 1); }, 1000); // return () => { clearInterval(intervalId); }; }, []); // пустой массив зависимостей означает, что эффект будет выполнен только при монтировании и размонтировании компонента // return <p>Seconds: {seconds}</p>; };
- useContext:
ХукuseContext
позволяет получить значение из контекста React в функциональных компонентах, без необходимости передавать данные через пропсы. Он принимает объект контекста, созданный с помощьюReact.createContext
, и возвращает текущее значение контекста. Пример:import React, { useContext } from 'react'; // const ThemeContext = React.createContext('light'); // const ThemedButton = () => { const theme = useContext(ThemeContext); // return <button>{theme}</button>; }; // const App = () => { return ( <ThemeContext.Provider value="dark"> <ThemedButton /> </ThemeContext.Provider> ); };
- useReducer:
ХукuseReducer
позволяет управлять состоянием компонента с помощью паттерна “редюсер”. Этот хук похож наuseState
, но предоставляет более мощный способ обновления состояния, особенно при сложных или зависимых от предыдущего состояния операциях. Он возвращает текущее состояние и функцию для его обновления, также как иuseState
. Пример:
import React, { useReducer } from 'react';
//
const initialState = { count: 0 };
//
const reducer = (state, action) => {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
};
//
const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState);
//
const increment = () => {
dispatch({ type: 'increment' });
};
//
const decrement = () => {
dispatch({ type: 'decrement' });
};
//
return (
<div>
<p>Count: {state.count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
};
- useCallback:
ХукuseCallback
позволяет кэшировать функцию, чтобы она сохраняла тот же экземпляр между рендерами компонента. Он позволяет кешировать функцию и перерасчет её значения, только когда изменяются зависимости. Это полезно, когда вы передаете функцию в дочерние компоненты с помощью пропсов, чтобы избежать ненужных перерисовок. Пример:import React, { useState, useCallback } from 'react'; // const CounterButton = ({ onClick }) => { // Колбэк-функция будет сохраняться между рендерами return <button onClick={onClick}>Increment</button>; }; // const Counter = () => { const [count, setCount] = useState(0); // const increment = useCallback(() => { setCount((prevCount) => prevCount + 1); }, []); // return ( <div> <p>Count: {count}</p> <CounterButton onClick={increment} /> </div> ); };
- useMemo:
ХукuseMemo
позволяет кэшировать вычисленное значение, чтобы оно сохранялось между рендерами компонента. Это полезно, когда вы должны вычислить сложное или ресурсоемкое значение, которое затем используется в компоненте. Пример:
import React, { useMemo } from 'react';
//
const ExpensiveComponent = ({ number }) => {
// Расчет затратного значения будет выполняться только тогда, когда
//
number изменится
const expensiveValue = useMemo(() => {
// Вычисления затратного значения
return calculateExpensiveValue(number);
}, [number]);
//
return <p>Expensive Value: {expensiveValue}</p>;
};
//
const App = () => {
const number = 42;
//
return <ExpensiveComponent number={number} />;
};
- useRef:
useRef позволяет получать доступ к DOM-элементам, а также хранить и получать значения этих элементов. Не вызывает ререндер компонента. ХукuseRef
возвращает изменяемый объект с полемcurrent
, которое может быть использовано для хранения мутирующих значений, которые не вызывают перерисовку компонента. Он полезен для сохранения/изменения значений между рендерами, обработки фокуса ввода или получения ссылок на DOM-элементы. Пример:import React, { useRef } from 'react'; // const TextInput = () => { const inputRef = useRef(); // const focusInput = () => { inputRef.current.focus(); }; // return ( <div> <input type="text" ref={inputRef} /> <button onClick={focusInput}>Focus Input</button> </div> ); };
Что можно сделать с помощью useReducer, чего нельзя сделать с помощью useState?
С useReducer можно реализовать более сложную логику состояния, к примеру, с несколькими значениями или зависимость нового состояния от старого.
Что такое batchUpdate и как он работает в React? Как решить проблему с тем что в функциональной компоненте в асинхронной функции при вызове setState - не работает batch update?
Batch update - это механизм оптимизации производительности в React, который позволяет обновлять компоненты пакетами вместо того, чтобы вызывать рендеринг после каждого изменения состояния. Чтобы решить проблему можно сгруппировать переменные состояния в один объект и использовать useReducer с этим объектом.