<StrictMode>
<StrictMode> позволяет находить распространённые ошибки в компонентах на ранних этапах разработки.
<StrictMode>
<App />
</StrictMode>
- Справочник
-
Использование
- Включение Strict Mode для всего приложения
- Включение Strict Mode для части приложения
- Исправление ошибок, обнаруженных при двойном рендеринге в режиме разработки
- Исправление ошибок, обнаруженных при повторном запуске эффектов в режиме разработки
- Исправление ошибок, обнаруженных при повторном запуске ref-колбэков в режиме разработки
- Исправление предупреждений об устаревших API, включённых в Strict Mode
Справочник
<StrictMode>
Используйте StrictMode, чтобы включить дополнительные проверки и предупреждения для дерева компонентов при разработке:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(
<StrictMode>
<App />
</StrictMode>
); Strict Mode включает следующие проверки только в режиме разработки:
- Ваши компоненты будут рендериться дополнительный раз, чтобы обнаружить ошибки, вызванные нечистым рендерингом.
- Эффекты ваших компонентов будут запускаться дополнительный раз, чтобы обнаружить ошибки, вызванные отсутствием очистки эффектов.
- Ref-колбэки ваших компонентов будут запускаться дополнительный раз, чтобы обнаружить ошибки, вызванные отсутствием очистки ref.
- Ваши компоненты будут проверяться на использование устаревших API.
Свойства
StrictMode не принимает свойств.
Предостережения
- Отключить Strict Mode внутри дерева, обёрнутого в
<StrictMode>, невозможно. Это позволяет быть уверенным, что все компоненты внутри<StrictMode>проходят проверку. Если две команды, работающие над продуктом, не могут договориться о ценности этих проверок, им нужно прийти к согласию или переместить<StrictMode>ниже по дереву.
Использование
Включение Strict Mode для всего приложения
Strict Mode включает дополнительные проверки, выполняемые только в режиме разработки, для всего дерева компонентов внутри компонента <StrictMode>. Эти проверки помогают находить распространённые ошибки в компонентах на ранних этапах разработки.
Чтобы включить Strict Mode для всего приложения, оберните корневой компонент в <StrictMode> при его рендеринге:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(
<StrictMode>
<App />
</StrictMode>
); Мы рекомендуем оборачивать в Strict Mode всё приложение, особенно если оно создано недавно. Если вы используете фреймворк, который вызывает для вас createRoot, ознакомьтесь с его документацией, чтобы узнать, как включить Strict Mode.
Хотя проверки Strict Mode выполняются только в режиме разработки, они помогают находить ошибки, уже существующие в коде, но которые трудно надёжно воспроизвести в production. Strict Mode позволяет исправить ошибки до того, как о них сообщат пользователи.
Примечание
В режиме разработки Strict Mode включает следующие проверки:
- Ваши компоненты будут рендериться дополнительный раз, чтобы обнаружить ошибки, вызванные нечистым рендерингом.
- Эффекты ваших компонентов будут запускаться дополнительный раз, чтобы обнаружить ошибки, вызванные отсутствием очистки эффектов.
- Ref-колбэки ваших компонентов будут запускаться дополнительный раз, чтобы обнаружить ошибки, вызванные отсутствием очистки ref.
- Ваши компоненты будут проверяться на использование устаревших API.
Все эти проверки выполняются только в режиме разработки и не влияют на production-сборку.
Включение Strict Mode для части приложения
Также можно включить Strict Mode для любой части приложения:
import { StrictMode } from 'react';
function App() {
return (
<>
<Header />
<StrictMode>
<main>
<Sidebar />
<Content />
</main>
</StrictMode>
<Footer />
</>
);
} В этом примере проверки Strict Mode не будут выполняться для компонентов Header и Footer. Однако они будут выполняться для Sidebar и Content, а также для всех вложенных в них компонентов, независимо от глубины вложенности.
Примечание
Если StrictMode включён для части приложения, React активирует только те режимы поведения, которые возможны в production. Например, если <StrictMode> не включён в корне приложения, эффекты не будут запускаться дополнительный раз при первоначальном монтировании, поскольку это привело бы к двойному запуску эффектов дочерних компонентов без запуска эффектов родительских компонентов, чего не может произойти в production.
Исправление ошибок, обнаруженных при двойном рендеринге в режиме разработки
React предполагает, что каждый написанный вами компонент является чистой функцией. Это означает, что написанные вами компоненты React должны всегда возвращать один и тот же JSX при одинаковых входных данных (props, state и context).
Компоненты, нарушающие это правило, ведут себя непредсказуемо и вызывают ошибки. Чтобы помочь обнаружить случайно написанный нечистый код, Strict Mode дважды в режиме разработки вызывает некоторые функции (только те, которые должны быть чистыми). К ним относятся:
- Тело функции компонента (только логика верхнего уровня, то есть код внутри обработчиков событий сюда не входит)
- Функции, передаваемые в
useState, функцииset,useMemoилиuseReducer - Некоторые методы классовых компонентов, например
constructor,render,shouldComponentUpdate(полный список)
Если функция чистая, её повторный запуск не меняет поведение, поскольку чистая функция каждый раз выдаёт одинаковый результат. Однако повторный запуск нечистой функции (например, функции, изменяющей полученные данные) обычно заметен (именно это и делает её нечистой!). Это помогает быстро обнаружить и исправить ошибку.
Вот пример, показывающий, как двойной рендеринг в Strict Mode помогает обнаруживать ошибки на раннем этапе.
Этот компонент StoryTray принимает массив stories и добавляет в его конец ещё один элемент «Создать историю»:
export default function StoryTray({ stories }) { const items = stories; items.push({ id: 'create', label: 'Create Story' }); return ( <ul> {items.map(story => ( <li key={story.id}> {story.label} </li> ))} </ul> ); }
В приведённом выше коде есть ошибка. Однако её легко не заметить, поскольку первоначальный результат выглядит правильно.
Эта ошибка станет заметнее, если компонент StoryTray будет рендериться несколько раз. Например, заставим StoryTray рендериться с другим цветом фона при каждом наведении курсора:
import { useState } from 'react'; export default function StoryTray({ stories }) { const [isHover, setIsHover] = useState(false); const items = stories; items.push({ id: 'create', label: 'Create Story' }); return ( <ul onPointerEnter={() => setIsHover(true)} onPointerLeave={() => setIsHover(false)} style={{ backgroundColor: isHover ? '#ddd' : '#fff' }} > {items.map(story => ( <li key={story.id}> {story.label} </li> ))} </ul> ); }
Обратите внимание: при каждом наведении курсора на компонент StoryTray элемент «Создать историю» снова добавляется в список. Код должен был добавить его один раз в конец списка. Но StoryTray напрямую изменяет массив stories из props. При каждом рендеринге StoryTray снова добавляет «Создать историю» в конец того же массива. Другими словами, StoryTray — нечистая функция: многократный вызов приводит к разным результатам.
Чтобы исправить эту проблему, можно создать копию массива и изменить её вместо исходного массива:
export default function StoryTray({ stories }) {
const items = stories.slice(); // Clone the array
// ✅ Good: Pushing into a new array
items.push({ id: 'create', label: 'Create Story' }); Так функция StoryTray станет чистой. При каждом вызове она будет изменять только новую копию массива и не затронет внешние объекты или переменные. Это решает проблему, но вам пришлось заставить компонент рендериться чаще, прежде чем стало очевидно, что в его поведении что-то не так.
В исходном примере ошибка была незаметна. Теперь обернём исходный (с ошибкой) код в <StrictMode>:
export default function StoryTray({ stories }) { const items = stories; items.push({ id: 'create', label: 'Create Story' }); return ( <ul> {items.map(story => ( <li key={story.id}> {story.label} </li> ))} </ul> ); }
Strict Mode всегда вызывает вашу функцию рендеринга дважды, поэтому ошибка сразу становится видна (элемент «Создать историю» появляется дважды). Так вы сможете обнаруживать подобные ошибки на ранних этапах. Исправив компонент так, чтобы он корректно работал в Strict Mode, вы также устраните многие возможные ошибки, которые могли бы возникнуть в production, например ошибку с наведением курсора из предыдущего примера:
import { useState } from 'react'; export default function StoryTray({ stories }) { const [isHover, setIsHover] = useState(false); const items = stories.slice(); // Clone the array items.push({ id: 'create', label: 'Create Story' }); return ( <ul onPointerEnter={() => setIsHover(true)} onPointerLeave={() => setIsHover(false)} style={{ backgroundColor: isHover ? '#ddd' : '#fff' }} > {items.map(story => ( <li key={story.id}> {story.label} </li> ))} </ul> ); }
Без Strict Mode эту ошибку легко было не заметить, пока вы не добавили бы больше повторных рендерингов. Strict Mode сразу выявил ту же ошибку. Strict Mode помогает находить ошибки до того, как вы отправите код своей команде и пользователям.
Подробнее о том, как поддерживать компоненты чистыми.
Примечание
Если у вас установлены React DevTools, вызовы console.log во время второго рендеринга будут отображаться немного бледнее. В React DevTools также есть настройка (по умолчанию отключена), которая полностью скрывает их.
Исправление ошибок, обнаруженных при повторном запуске эффектов в режиме разработки
Strict Mode также помогает находить ошибки в эффектах.
У каждого эффекта есть код настройки и, возможно, код очистки. Обычно React вызывает настройку, когда компонент монтируется (добавляется на экран), и вызывает очистку, когда компонент размонтируется (удаляется с экрана). Если зависимости изменились с момента последнего рендеринга, React затем снова вызывает очистку и настройку.
Когда Strict Mode включён, React также выполняет в режиме разработки один дополнительный цикл настройки и очистки для каждого эффекта. Это может показаться неожиданным, но помогает выявить тонкие ошибки, которые трудно обнаружить вручную.
Вот пример, показывающий, как повторный запуск эффектов в Strict Mode помогает обнаруживать ошибки на раннем этапе.
Рассмотрим пример, в котором компонент подключается к чату:
import { createRoot } from 'react-dom/client'; import './styles.css'; import App from './App'; const root = createRoot(document.getElementById("root")); root.render(<App />);
В этом коде есть проблема, хотя она может быть не сразу очевидна.
Чтобы сделать проблему заметнее, добавим функциональность. В примере ниже roomId не задано жёстко. Вместо этого пользователь может выбрать в раскрывающемся списке roomId, к которому нужно подключиться. Нажмите «Открыть чат», затем по очереди выбирайте разные комнаты чата. Следите за количеством активных подключений в консоли:
import { createRoot } from 'react-dom/client'; import './styles.css'; import App from './App'; const root = createRoot(document.getElementById("root")); root.render(<App />);
Вы заметите, что количество открытых подключений постоянно растёт. В реальном приложении это привело бы к проблемам с производительностью и сетью. Проблема в том, что в вашем эффекте отсутствует функция очистки:
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, [roomId]); Теперь эффект выполняет очистку после себя и закрывает устаревшие подключения, поэтому утечка устранена. Однако обратите внимание: проблема стала заметна только после добавления дополнительной функциональности (списка выбора).
В исходном примере ошибка была незаметна. Теперь обернём исходный (с ошибкой) код в <StrictMode>:
import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import './styles.css'; import App from './App'; const root = createRoot(document.getElementById("root")); root.render( <StrictMode> <App /> </StrictMode> );
В Strict Mode проблема сразу становится видна (количество активных подключений увеличивается до 2). Strict Mode выполняет дополнительный цикл настройки и очистки для каждого эффекта. В этом эффекте нет логики очистки, поэтому он создаёт дополнительное подключение, но не закрывает его. Это указывает на отсутствие функции очистки.
Strict Mode позволяет обнаруживать подобные ошибки на ранних этапах. Добавив функцию очистки и исправив эффект в Strict Mode, вы также устраните многие возможные ошибки, которые могли бы возникнуть в production, например проблему со списком выбора из предыдущего примера:
import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import './styles.css'; import App from './App'; const root = createRoot(document.getElementById("root")); root.render( <StrictMode> <App /> </StrictMode> );
Обратите внимание: количество активных подключений в консоли больше не растёт.
Без Strict Mode легко было не заметить, что эффекту нужна очистка. Выполняя в режиме разработки для эффекта цикл настройка → очистка → настройка вместо одного лишь настройки, Strict Mode помог выявить отсутствие логики очистки.
Подробнее о реализации очистки эффектов.
Исправление ошибок, обнаруженных при повторном запуске ref-колбэков в режиме разработки
Strict Mode также помогает находить ошибки в ref-колбэках.
У каждого callback ref есть код настройки и, возможно, код очистки. Обычно React вызывает настройку, когда элемент создаётся (добавляется в DOM), и вызывает очистку, когда элемент удаляется (удаляется из DOM).
Когда Strict Mode включён, React также выполняет в режиме разработки один дополнительный цикл настройки и очистки для каждого callback ref. Это может показаться неожиданным, но помогает выявить тонкие ошибки, которые трудно обнаружить вручную.
Рассмотрим пример, в котором можно выбрать животное и прокрутить страницу до него. Обратите внимание: при переключении с «Кошек» на «Собак» в консоли отображается, что количество животных в списке продолжает расти, а кнопки «Прокрутить к» перестают работать:
import { useRef, useState } from "react"; export default function CatFriends() { const itemsRef = useRef([]); const [catList, setCatList] = useState(setupCatList); const [cat, setCat] = useState('neo'); function scrollToCat(index) { const list = itemsRef.current; const {node} = list[index]; node.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center", }); } const cats = catList.filter(c => c.type === cat) return ( <> <nav> <button onClick={() => setCat('neo')}>Neo</button> <button onClick={() => setCat('millie')}>Millie</button> </nav> <hr /> <nav> <span>Scroll to:</span>{cats.map((cat, index) => ( <button key={cat.src} onClick={() => scrollToCat(index)}> {index} </button> ))} </nav> <div> <ul> {cats.map((cat) => ( <li key={cat.src} ref={(node) => { const list = itemsRef.current; const item = {cat: cat, node}; list.push(item); console.log(`✅ Adding cat to the map. Total cats: ${list.length}`); if (list.length > 10) { console.log('❌ Too many cats in the list!'); } return () => { // 🚩 No cleanup, this is a bug! } }} > <img src={cat.src} /> </li> ))} </ul> </div> </> ); } function setupCatList() { const catList = []; for (let i = 0; i < 10; i++) { catList.push({type: 'neo', src: "https://placecats.com/neo/320/240?" + i}); } for (let i = 0; i < 10; i++) { catList.push({type: 'millie', src: "https://placecats.com/millie/320/240?" + i}); } return catList; }
Это ошибка, которая проявится в production! Поскольку ref-колбэк не удаляет животных из списка при очистке, список животных продолжает расти. Это утечка памяти, которая может привести к проблемам с производительностью в реальном приложении и нарушить его работу.
Проблема в том, что ref-колбэк не выполняет очистку:
<li
ref={node => {
const list = itemsRef.current;
const item = {animal, node};
list.push(item);
return () => {
// 🚩 No cleanup, this is a bug!
}
}}
</li> Теперь обернём исходный (с ошибкой) код в <StrictMode>:
import { useRef, useState } from "react"; export default function CatFriends() { const itemsRef = useRef([]); const [catList, setCatList] = useState(setupCatList); const [cat, setCat] = useState('neo'); function scrollToCat(index) { const list = itemsRef.current; const {node} = list[index]; node.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center", }); } const cats = catList.filter(c => c.type === cat) return ( <> <nav> <button onClick={() => setCat('neo')}>Neo</button> <button onClick={() => setCat('millie')}>Millie</button> </nav> <hr /> <nav> <span>Scroll to:</span>{cats.map((cat, index) => ( <button key={cat.src} onClick={() => scrollToCat(index)}> {index} </button> ))} </nav> <div> <ul> {cats.map((cat) => ( <li key={cat.src} ref={(node) => { const list = itemsRef.current; const item = {cat: cat, node}; list.push(item); console.log(`✅ Adding cat to the map. Total cats: ${list.length}`); if (list.length > 10) { console.log('❌ Too many cats in the list!'); } return () => { // 🚩 No cleanup, this is a bug! } }} > <img src={cat.src} /> </li> ))} </ul> </div> </> ); } function setupCatList() { const catList = []; for (let i = 0; i < 10; i++) { catList.push({type: 'neo', src: "https://placecats.com/neo/320/240?" + i}); } for (let i = 0; i < 10; i++) { catList.push({type: 'millie', src: "https://placecats.com/millie/320/240?" + i}); } return catList; }
В Strict Mode проблема сразу становится видна. Strict Mode выполняет дополнительный цикл настройки и очистки для каждого callback ref. У этого callback ref нет логики очистки, поэтому он добавляет refs, но не удаляет их. Это указывает на отсутствие функции очистки.
Strict Mode помогает заранее находить ошибки в callback refs. Добавив функцию очистки и исправив колбэк в Strict Mode, вы также устраните многие возможные ошибки, которые могли бы возникнуть в production, например проблему с кнопкой «Прокрутить к» из предыдущего примера:
import { useRef, useState } from "react"; export default function CatFriends() { const itemsRef = useRef([]); const [catList, setCatList] = useState(setupCatList); const [cat, setCat] = useState('neo'); function scrollToCat(index) { const list = itemsRef.current; const {node} = list[index]; node.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center", }); } const cats = catList.filter(c => c.type === cat) return ( <> <nav> <button onClick={() => setCat('neo')}>Neo</button> <button onClick={() => setCat('millie')}>Millie</button> </nav> <hr /> <nav> <span>Scroll to:</span>{cats.map((cat, index) => ( <button key={cat.src} onClick={() => scrollToCat(index)}> {index} </button> ))} </nav> <div> <ul> {cats.map((cat) => ( <li key={cat.src} ref={(node) => { const list = itemsRef.current; const item = {cat: cat, node}; list.push(item); console.log(`✅ Adding cat to the map. Total cats: ${list.length}`); if (list.length > 10) { console.log('❌ Too many cats in the list!'); } return () => { list.splice(list.indexOf(item)); console.log(`❌ Removing cat from the map. Total cats: ${itemsRef.current.length}`); } }} > <img src={cat.src} /> </li> ))} </ul> </div> </> ); } function setupCatList() { const catList = []; for (let i = 0; i < 10; i++) { catList.push({type: 'neo', src: "https://placecats.com/neo/320/240?" + i}); } for (let i = 0; i < 10; i++) { catList.push({type: 'millie', src: "https://placecats.com/millie/320/240?" + i}); } return catList; }
Теперь при первоначальном монтировании в StrictMode все ref-колбэки сначала настраиваются, затем очищаются и настраиваются снова:
...
✅ Adding animal to the map. Total animals: 10
...
❌ Removing animal from the map. Total animals: 0
...
✅ Adding animal to the map. Total animals: 10 Это ожидаемое поведение. Strict Mode подтверждает, что ref-колбэки очищаются правильно, поэтому размер списка не превышает ожидаемого значения. После исправления утечки памяти отсутствуют, а все функции работают как положено.
Без Strict Mode эту ошибку легко было не заметить, пока вы не начали бы пользоваться приложением и не обнаружили, что некоторые функции работают неправильно. Strict Mode выявил ошибки сразу — до того, как вы отправили код в production.
Исправление предупреждений об устаревших API, включённых в Strict Mode
React предупреждает, если какой-либо компонент внутри дерева <StrictMode> использует один из следующих устаревших API:
-
UNSAFE_методы жизненного цикла классов, напримерUNSAFE_componentWillMount. См. альтернативы.
Эти API в основном используются в старых классовых компонентах, поэтому в современных приложениях они встречаются редко.
© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://react.dev/reference/react/StrictMode