Понимание поведения ловушек useEffect () и useState () - PullRequest
0 голосов
/ 11 марта 2020

Итак, у меня есть этот бит кода, который работает не так, как ожидалось. Текущий фокус был установлен с помощью useState () на родительском компоненте, следовательно, это переменная состояния. Однако, когда значение currentFocus изменяется в родительском элементе, переменная focus здесь сама по себе не обновляется. Я ожидал бы, что рендеринг родительского компонента, который, в свою очередь, рендерит этот компонент, вызовет изменение значения foucs.

import React, { useRef, useEffect, useState } from 'react';
const CookieDetails = props => {
  const {
    name,
    cost,
    value,
    numOwned,
    onMouseClick,
    cookieId,
    currentFocus,
  } = props;

  let cookieInfoRef = useRef(null);
  //My focus doesnt change even if I change currentFocus in parent component
  const [focus, setFocus] = useState(currentFocus);

  useEffect(() => {
    console.log('currentFocus', currentFocus);
    console.log('focus', focus);
    console.log('cookieID', cookieId); 
    if (cookieInfoRef.current && cookieId === focus) {
      console.log('current', cookieInfoRef.current);
      cookieInfoRef.current.focus();
    }
  }, [focus]);

  return (
    <React.Fragment>
      <button
        onClick={onMouseClick}
        ref={cookieId === focus ? cookieInfoRef : null}
      >
        <h3>{name}</h3>
        <p>Cost:{cost}</p>
        <p>Value:{value}</p>
        <p>Owned:{numOwned}</p>
      </button>
    </React.Fragment>
  );
};

export default CookieDetails;

Теперь я могу решить эту проблему, выполнив следующие действия:

import React, { useRef, useEffect, useState } from 'react';
const CookieDetails = props => {
  const {
    name,
    cost,
    value,
    numOwned,
    onMouseClick,
    cookieId,
    currentFocus,
  } = props;

  let cookieInfoRef = useRef(null);

  useEffect(() => {
    console.log('currentFocus', currentFocus);
    console.log('cookieID', cookieId);        
    if (cookieInfoRef.current && cookieId === currentFocus) {
      console.log('current', cookieInfoRef.current);
      cookieInfoRef.current.focus();
    }
  });

  return (
    <React.Fragment>
      <button
        onClick={onMouseClick}
        ref={cookieId === currentFocus ? cookieInfoRef : null}
      >
        <h3>{name}</h3>
        <p>Cost:{cost}</p>
        <p>Value:{value}</p>
        <p>Owned:{numOwned}</p>
      </button>
    </React.Fragment>
  );
};

export default CookieDetails;

Но я хотел запускать ловушку useEffect только при обновлении focus / currentFocus, а не после каждого рендера. , Так почему это происходит? Чего мне не хватает, чтобы понять здесь.

Также ранее я заметил, что если вы сделали что-то подобное, функция handleStuff всегда использует начальное значение 100 (то есть всегда 100 + 10) вместо увеличения на 10 при каждом нажатии клавиши. Я могу решить эту проблему, удалив пустой [] в качестве второго аргумента в useEffect. Однако я ожидал, что handleStuff по-прежнему будет обновляться с использованием самого последнего значения, учитывая, что eventListner уже был добавлен при первоначальном рендеринге, а при втором нажатии клавиши он должен добавить 10 к 110 вместо 100, но он продолжает использовать значение начального состояния 100 вместо. Почему вы должны очистить старого слушателя и добавлять нового каждый раз, чтобы он работал?

[value, setValue] = useState(100)

handleStuff = (event) => {
 setValue(value+10)
}

useEffect(() => {
  window.addEventListener('keydown', handleStuff)
  return () => {
    window.removeEventListener('keydown', handleStuff)
  }
 },[]);

Я не особо заинтересован в решениях, я действительно заинтересован в понимании того, как перехватчики useEffect () и useState () работают в этих условиях.

1 Ответ

4 голосов
/ 11 марта 2020

Эй, ловушка useEffect может немного сбить с толку. Но способ думать об этом -

useEffect(() => {
  // Called every render
})

useEffect(() => {
  // Called on first render
}, [])

useEffect(() => {
  // Called when x y & z updates
}, [x, y, z])

Проблема в том, что вы не слушаете текущее обновление Focus в своем коде.

useEffect(() => {
  // Called when focus updates
}, [focus]);

useEffect(() => {
  // Called when props.currentFocus & focus updates
}, [props.currentFocus, focus]);

Теперь, чтобы объяснить вашу путаницу:

// My focus doesnt change even if I change currentFocus in parent component
const [focus, setFocus] = useState(currentFocus);

Когда вы передаете currentFocus здесь, единственный раз, когда значение currentFocus передается в фокус, useState находится на первом рендере. Поэтому вам нужно прослушать текущее обновление Focus и затем установить новый фокус, который должен работать так, как вы хотите!

// Focus set to props.currentFocus on first render
const [focus, setFocus] = useState(currentFocus);

useEffect(() => {
  // Update focus
  setFocus(props.currentFocus)
}, [props.currentFocus])

useEffect(() => {
  // currentFocus will be the same as focus now
  console.log('currentFocus', currentFocus);
  console.log('focus', focus);
  console.log('cookieID', cookieId); 
  if (cookieInfoRef.current && cookieId === focus) {
    console.log('current', cookieInfoRef.current);
    cookieInfoRef.current.focus();
  }
}, [focus]);

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...