React useEffect, включая отсутствующую зависимость, сломает его

Я работаю над приложением React с некоторыми useEffect хуками. Допустим, у меня есть следующий код:

import React, { useState, useEffect } from 'react';

export default () => {
  const [fooArr, setFooArr] = useState([]);
  const [barObj, setBarObj] = useState({});

  return <h1>{barObj.name + " " + barObj.status}</h1>
}

Но теперь проблема. fooArr изменяется где-то еще, и я хочу обновить barObj, когда fooArr изменится. Я сделал это, как показано ниже:

import React, { useState, useEffect } from 'react';

export default () => {
  const [fooArr, setFooArr] = useState([]);
  const [barObj, setBarObj] = useState({});

  // >>> some fetching and setting of 'fooArr' here <<<

  useEffect(() => {
    setBarObj(barObj => {
      let _barObj = { ...barObj };
      _barObj.status = fooArr[1];
      return _barObj;
    })
  }, [fooArr]);

  return <h1>{barObj.name + " " + barObj.status}</h1>
}

Однако это дает мне следующую ошибку React Hook useEffect has a missing dependency: 'barObj' and 'setBarObj'. Either include it or remove the dependency array. Я точно знаю, что это означает, но когда я включаю его, я получаю бесконечный цикл повторного рендеринга, потому что он продолжает обновляться. Теперь у меня // eslint-disable-line рядом с массивом зависимостей, чтобы это игнорировать. Но я чувствую, что этого никогда не следует делать.

Как мне с этим справиться? Я бы хотел, чтобы не было сообщения об ошибке, но также не было бесконечного цикла повторного рендеринга.

Пример с дополнительным кодом, похожим на мой код:

useEffect(() => {
  setBarObj(prevBarObj => {
    let _barObj = { ...prevBarObj };
    if(_barObj.status.includes('hello') {
      _barObj.status += "world"
    } else {
      _barObj.status = "other"
    }
    return _barObj;
  })
}, [fooArr])

person Thimma    schedule 26.05.2020    source источник
comment
Отвечает ли это на ваш вопрос? Передача массива в список зависимостей useEffect   -  person Luuuud    schedule 26.05.2020
comment
попробуйте переименовать barObj внутри useEffect, например setBarObj (prevBarObj = ›{...   -  person Nikita Madeev    schedule 26.05.2020


Ответы (2)


Это должно работать нормально:

useEffect(() => {
  setBarObj(barObj => ({
    ...barObj,
    status: fooArr[1]
  })
}, [fooArr]);

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


Согласно вашему комментарию, вы можете:

useEffect(() => {
  if (barObj.status === 'hello') return
  setBarObj(barObj => ({
    ...barObj,
    status: fooArr[1]
  })
}, [fooArr]);

С обновленным запросом вы можете использовать что-то вроде:

useEffect(() => {
  setBarObj(barObj => {
    const updatedStatus = barObj.status === 'hello' ? (barObj.status + 'world') : fooArr[1]
    return {
    ...barObj,
    status: updatedStatus
  }
}, [fooArr]);
person Bhojendra Rauniyar    schedule 26.05.2020
comment
но что, если мне нужно внести различные изменения в этот объект в setBarObj ?, например: setBarObj(barObj => { if(barObj.status === "hello") return {} else return barObj }; - person Thimma; 26.05.2020
comment
Я обновил свой ответ, добавив немного более сложную работу, которую я использую, пожалуйста, посмотрите, если хотите :-) - person Thimma; 26.05.2020
comment
Вам также нужно будет использовать setBarObj с этим условием. Я обновлю свой ответ. - person Bhojendra Rauniyar; 26.05.2020

Я думаю, что отображается предупреждение об отсутствующей зависимости, потому что вы затеняет barObj состояние. Попробуйте использовать другое имя аргумента и избегайте копирования объекта:

useEffect(() => {
    setBarObj(bar => {
      return {...bar, status: fooArr[1]};
    })
  }, [fooArr]);
person Clarity    schedule 26.05.2020