useEffect не работает при изменении значения зависимости - PullRequest
5 голосов
/ 03 февраля 2020

Я испытал функцию useEffect из ловушки React. Когда я использую его с useSelector из React-redux, это работало так странно.

Мой редуктор:

const initialState = { a: 0 };

function mainReducer(state = initialState, action) {
  const { type, payload } = action;
  switch (type) {
    case 'A': return { ...state, a: payload }
    default:
      return state;
  }
}

Мой компонент:

function MyComponent(props) {
  const { a } = useSelector(state => state.mainReducer);
  const dispatch = useDispatch(); 

  useEffect(() => {
    console.log('did mount: ', a);
    dispatch({ type: 'A', payload: 1 })
  }, []); 

  useEffect(() => {
    console.log('use effect: ', a);
    dispatch({ type: 'A', payload: a });
  }, [a]) 

  return (<View style={styles.container}>
    <Text style={styles.text}>{a}</Text>
  </View>);
};

Результат

Журнал:

did mount ran: 0
useEffect ran: 0

Последний result является переменной 'a' = 0

????

Как я понимаю, после первого рендеринга оба эффекта выполнялись последовательно в своем порядке в коде.
(Шаг 1 ) Так что первый эффект запуска fist -> log 'сделал mount run: 0'. Затем он отправляет значение 1 для хранения
(Шаг 2). Второй эффект запускается после -> log 'did mount run: 0'. Затем он отправляет значение 0 для хранения

Но я не понимаю, что второй эффект должен отслеживать изменение из переменной 'a', поэтому будет:
В следующее время рендеринга:
(Шаг 3) второй useEffect следует запускать, когда значение 'a' изменяется с 0 на 1 (с шага 1).
А затем:
(Шаг 4) должно быть третье повторное рендеринг, когда значение снова меняется с 1 на 0 (с шага 2)

Таким образом, журнал должен быть:

did mount ran: 0
useEffect ran: 0
useEffect ran: 1
useEffect ran: 0

Не могли бы вы объяснить мне, что я скучаю? Спасибо

Ответы [ 2 ]

4 голосов
/ 03 февраля 2020

Ваша первая диспетчеризация вызывается после первого рендера, поэтому даже до того, как ваше второе значение рендеринга будет равно 0, так что ваш второй useEffect не сможет обнаружить изменение, поскольку изменений нет.

Давайте посмотрим, что происходит в вашем метод визуализации

Первый рендер:

a = 0

first useEffect: dispatch ({a: 1})

second useEffect: dispatch ({a: 0})

, так что теперь в вашем хранилище резервов a равно 0.

Second Render

a = 0

first useEffect: не запускается, поскольку нет зависимости

second useEffect: не запускается, так как не изменено.

1 голос
/ 03 февраля 2020

ПОЖАЛУЙСТА, прекратите использовать

 useSelector(state => state.mainReducer);

, в этом нет никакого смысла

должно быть простое преобразование состояний (подпункт)

const a = useSelector(state => state.a)

, принимаемое напрямую Из документов Redx:

const counter = useSelector(state => state.counter)  

Обновление

Вы можете увидеть эффект (из-за смены магазина) со слегка измененным компонентом

function MyComponent(props) {
  const a = useSelector(state => state.a);
  const dispatch = useDispatch(); 

  console.log('render: ', a);

  useEffect(() => {
    console.log('use effect: ', a);
    dispatch({ type: 'A', payload: a });
  }, [a]) 

  useEffect(() => {
    console.log('did mount: ', a);
    dispatch({ type: 'A', payload: 1 })
  }, []); 

  return (<View style={styles.container}>
    <Text style={styles.text}>{a}</Text>
  </View>);
};

Это должно привести к журналу:

  • render: 0 // начальное состояние
  • use effect: 0 // первый запуск эффекта
  • // диспетчеризация 0 ... обработано в хранилище редуктором, но результаты в том же состоянии ...
    // ... и в нашем процессе рендеринга мы все еще работаем над "старым" a, прочитанным из состояния в начале рендеринга
  • did mount: 0 // 'old' a
    // диспетчеризация 1 ... измененное состояние в хранилище с избыточностью
  • .... отображаемый текст 0
    ...
    ...

  • // useSelector принудительное повторное отображение - обнаружено изменение

  • render: 1 // последнее отправленное значение, обработанное редукторами в новое состояние, прочитано селектором * 10 50 *
  • use effect: 1 // useEffect работает, как ОЖИДАЕТСЯ, как эффект a change
  • .... предоставленный текст 1

...
...

  • больше никаких повторных обращений - состояние последней отправки не изменилось

Конечно, отправка из другого компонента приведет к обновлению в этот компонент ... если значение будет другим.

...