Могу ли я установить состояние внутри хука useEffect

Допустим, у меня есть какое-то состояние, которое зависит от какого-то другого состояния (например, когда A меняется, я хочу, чтобы B изменился).

Уместно ли создавать ловушку, которая наблюдает за A и устанавливает B внутри ловушки useEffect?

Будут ли эффекты каскадироваться так, что, когда я нажму кнопку, первый эффект сработает, что приведет к изменению b, в результате чего сработает второй эффект перед следующим рендером? Есть ли какие-либо недостатки в производительности для структурирования кода, подобного этому?

let MyComponent = props => {
  let [a, setA] = useState(1)
  let [b, setB] = useState(2)
  useEffect(
    () => {
      if (/*some stuff is true*/) {
        setB(3)
      }
    },
    [a],
  )
  useEffect(
    () => {
      // do some stuff
    },
    [b],
  )

  return (
    <button
      onClick={() => {
        setA(5)
      }}
    >
      click me
    </button>
  )
}

Ответ 1

Эффекты всегда выполняются после завершения фазы рендеринга, даже если вы установите setState внутри одного эффекта, другой эффект прочитает обновленное состояние и выполнит действие только после фазы рендеринга.

Сказав, что, вероятно, лучше выполнить оба действия с одинаковым эффектом, если только не существует вероятность того, что b может измениться по причинам, отличным от changing a в этом случае вы также захотите выполнить ту же логику

Ответ 2

Использование setState внутри useEffect создаст бесконечный цикл, который, скорее всего, вы не хотите вызывать.

useEffect вызывается после каждого рендера, и когда внутри него используется setState, он вызывает повторный рендеринг компонента, который вызывает useEffect и т.д. и т.д.

Единственный случай, когда использование useState внутри useEffect не вызовет бесконечный цикл, - это когда вы передаете пустой массив в качестве второго аргумента для useEffect например useEffect(() => {....}, []) что означает, что эффект Функция должна вызываться один раз: только после первого монтирования/рендеринга.

Ответ 3

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

например.

useEffect(myeffect, [])

Вышеуказанный эффект будет срабатывать только после рендеринга компонента. это похоже на жизненный цикл componentDidMount

const [something, setSomething] = withState(0)
const [myState, setMyState] = withState(0)
useEffect(() => {
  setSomething(0)
}, myState)

Вышеуказанный эффект будет вызывать только мое состояние, которое изменилось. Это похоже на componentDidUpdate, за исключением того, что не каждое изменяемое состояние будет запускать его.

Вы можете прочитать более подробно, хотя эту ссылку