Написал код, который должен обновить состояние 1 раз, но где-то что-то обновляет его ещё раз сразу же после первого раза. Можно ли как-то получить Stack-Trace при обновлении состояния в React, чтобы посмотреть, что его обновляет?
-
выведите console.log состояния в местах его изменения и смотрите что происходит при загрузке странице, если состояние хранится в redux, то есть прагин для браузера, там можно посмотреть вызываемые события и все изменения store по ним. Скорее всего состояние обновляется несколько раз из-за лишних рендеров, которые не было запланированы, это можно решить установкой условий для смены состояний только в определенные моменты – MasterAlex Aug 29 '19 at 08:59
2 Answers
Если вы хотите узнать краткий фрагмент без каких-либо внешних зависимостей, то можно пойти простым путём, через метод componentDidUpdate вывести информацию:
componentDidUpdate(prevProps, prevState) {
Object.entries(this.props).forEach(([key, val]) =>
prevProps[key] !== val && console.log(`Prop '${key}' changed`)
);
Object.entries(this.state).forEach(([key, val]) =>
prevState[key] !== val && console.log(`State '${key}' changed`)
);
}
componentDidUpdate()- вызывается сразу после обновления. Не вызывается при первом рендере. Метод позволяет работать с DOM при обновлении компонента.
Еще можно заюзать небольшой хук, для отслеживания обновлений функций компонентов:
function useTraceUpdate(props) {
const prev = useRef(props);
useEffect(() => {
const changedProps = Object.entries(props).reduce((accumulator, [key, value]) => {
// если значение изменилось - вернем его в результирующем объекте
if (prev.current[key] !== value) {
accumulator[key] = [prev.current[key], value];
}
return accumulator;
}, {});
if (Object.keys(changedProps).length > 0) {
console.log('Changed props:', changedProps);
}
prev.current = props;
});
}
// Использование
function MyComponent(props) {
useTraceUpdate(props);
return <div>{props.children}</div>;
}
Дополнения к коду:
Хук эффекта
useEffectдаёт вам возможность выполнять побочные эффекты в функциональном компоненте. ХукuseEffectпредставляет собой совокупность методовcomponentDidMount,componentDidUpdate, иcomponentWillUnmount.
useRefвозвращает изменяемый ref-объект, свойство.currentкоторого инициализируется переданным аргументом (initialValue). Возвращённый объект будет сохраняться в течение всего времени жизни компонента.Метод
reduce()применяет функцию reducer к каждому элементу массива (слева-направо), возвращая одно результирующее значение.accumulator- значение, которое возвращает функцияcallbackпосле посещения очередного элемента, либо значениеinitialValue, если оно предоставлено
Ссылка на источник: Trace why a React component is re-rendering. Думаю, что этого будет достаточно, чтобы отследить изменения. Также, можно поставить брэйкпоинт (debugger;) и посмотреть по стэку вызовов в браузере, откуда растут ноги.
- 13,958
-
Напишите пожалуйста комментарии к вашему коду (во втором примере) а то имя переменных состоит из одной буквы и очень сложно догадаться что они делают. – Randall Aug 29 '19 at 10:09
-
@Demon__ANT простите, а что именно не понятно? Вы про метод
reduceи аргументы колбэка внутри него? – Denis Bubnov Aug 29 '19 at 10:12 -
-
Есть пакет https://www.npmjs.com/package/why-did-you-update, который делает примерно то же самое из коробки – Aug 29 '19 at 10:25
-
Вот набор библиотек/компонентов/техник, которые решают вашу проблему https://github.com/markerikson/redux-ecosystem-links/blob/master/devtools.md#component-update-monitoring
Особо выделю https://github.com/reactopt/reactopt
- 548
-
4Было бы неплохо показать чуть более подробно как это будет решать. На текущий момент выглядит не как полноценный ответ, а как некоторое общее указание в какой стороне искать способ решения проблемы. Обратите внимание: поле ответ предназначено для исчерпывающих и полных ответов, у вас же пока скорее хороший комментарий. – A K Aug 28 '19 at 13:38
-
ну, тут нет конкретного ответа, без примера кода от @JamesJGoodwin, кто-то меняет props/state и происходит перерисовка ;) – Mike Aug 28 '19 at 13:47