4

Написал код, который должен обновить состояние 1 раз, но где-то что-то обновляет его ещё раз сразу же после первого раза. Можно ли как-то получить Stack-Trace при обновлении состояния в React, чтобы посмотреть, что его обновляет?

Denis Bubnov
  • 13,958
  • выведите console.log состояния в местах его изменения и смотрите что происходит при загрузке странице, если состояние хранится в redux, то есть прагин для браузера, там можно посмотреть вызываемые события и все изменения store по ним. Скорее всего состояние обновляется несколько раз из-за лишних рендеров, которые не было запланированы, это можно решить установкой условий для смены состояний только в определенные моменты – MasterAlex Aug 29 '19 at 08:59

2 Answers2

3

Если вы хотите узнать краткий фрагмент без каких-либо внешних зависимостей, то можно пойти простым путём, через метод 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;) и посмотреть по стэку вызовов в браузере, откуда растут ноги.

Denis Bubnov
  • 13,958
  • Напишите пожалуйста комментарии к вашему коду (во втором примере) а то имя переменных состоит из одной буквы и очень сложно догадаться что они делают. – Randall Aug 29 '19 at 10:09
  • @Demon__ANT простите, а что именно не понятно? Вы про метод reduce и аргументы колбэка внутри него? – Denis Bubnov Aug 29 '19 at 10:12
  • Про все что внутри хука useEffect – Randall Aug 29 '19 at 10:15
  • Есть пакет https://www.npmjs.com/package/why-did-you-update, который делает примерно то же самое из коробки –  Aug 29 '19 at 10:25
  • @DenisBubnov спасибо – Randall Aug 29 '19 at 11:19
0

Вот набор библиотек/компонентов/техник, которые решают вашу проблему https://github.com/markerikson/redux-ecosystem-links/blob/master/devtools.md#component-update-monitoring

Особо выделю https://github.com/reactopt/reactopt

Mike
  • 548
  • 4
    Было бы неплохо показать чуть более подробно как это будет решать. На текущий момент выглядит не как полноценный ответ, а как некоторое общее указание в какой стороне искать способ решения проблемы. Обратите внимание: поле ответ предназначено для исчерпывающих и полных ответов, у вас же пока скорее хороший комментарий. – A K Aug 28 '19 at 13:38
  • ну, тут нет конкретного ответа, без примера кода от @JamesJGoodwin, кто-то меняет props/state и происходит перерисовка ;) – Mike Aug 28 '19 at 13:47