Крюк useEffect не срабатывает после изменения состояния - PullRequest
0 голосов
/ 10 февраля 2019

У меня есть два родственных компонента, которые разделяют состояние через контекст в реакции.Общим состоянием между компонентами является массив.

Если я обновляю состояние arr в одном компоненте, я хочу, чтобы другой компонент прослушал это обновление и сделал что-то соответственно.Когда я использую useEffect во втором компоненте, я прослушиваю изменения в переменной состояния arr.

Например:

// App Component -------
const App = props => {
 const { arr, setArr } = useContext(GlobalContext)

 const handleChange = () => {
   const newArr = arr
   [10, 20, 30, 40].map(v => {
     newArr.push(v)
     setArr(newArr)
   })

  return (...)
}

// App2 (Sibling) Component 
const App2 = props => {
  const { arr, setArr } = useContext(GlobalContext)
  const [localArr, setLocalArr] = useState(0)

  useEffect(
    () => {
      updateLocalState()
    },
    // fire if "arr" gets updated
    [arr]
  )

  const updateLocalState = () => {
    setLocalArr(localArr + 1)
  }

  return (...)
}

Хук useEffect равен только запускается при начальном рендеринге, хотя состояние arr обновляется.

Я знаю, что объявление новой переменной const newArr = arr для моей переменной состояния является ссылкой, поэтому newArr.push(v) технически является мутацией состояния. Однако состояние все еще обновляется, предупреждение не выдается, и useEffect ничего не делает.

Почему не вызывается useEffect, хотя состояние обновляется?Это из-за мутации состояния?

Второй вопрос: почему не возникает предупреждение или ошибка в отношении мутации состояния?Мутации состояний опасны - если это произойдет, я ожидаю какого-то предупреждения.

Демонстрация здесь:

Edit 7wzlo8y4m1

1 Ответ

0 голосов
/ 11 февраля 2019

Массив, который вы передаете в качестве второго аргумента useEffect, проверяет только, являются ли элементы в массиве === для элементов в нем в предыдущем рендере.const newArr = arr; приведет к newArr === arr, поскольку он не создает новый массив, а это не то, что вам нужно.

Создайте новый массив со всеми элементами в arr, и он будет работать как положено.

const App = props => {
 const { arr, setArr } = useContext(GlobalContext)

 const handleChange = () => {
   const newArr = [...arr]
   [10, 20, 30, 40].forEach(v => {
     newArr.push(v)
   })
   setArr(newArr)
 }

  return <>{/* ... */}</>
}
...