理解 useEffect() 和 useState() 钩子的行为

ssa*_*uif 0 javascript reactjs react-hooks use-effect use-state

所以我有这段代码不能按预期工作。当前焦点是在父组件上使用 useState() 设置的,因此它是一个状态变量。但是,当父级中的 currentFocus 值发生变化时,这里的焦点变量本身不会更新。我本来希望重新渲染父组件,而重新渲染该组件会导致 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;
Run Code Online (Sandbox Code Playgroud)

现在我可以通过执行以下操作来解决这个问题,

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;
Run Code Online (Sandbox Code Playgroud)

但是我只想在更新 focus/currentFocus 时而不是在每次渲染之后运行 useEffect 钩子。那么为什么会发生这种情况呢?我在这里想了解什么。

另外我之前注意到,如果你做了这样的事情,handleStuff 函数总是使用 100 的初始值(所以它总是 100 + 10)而不是每次按下一个键时增加 10。我可以通过删除空 [] 作为 useEffect 中的第二个参数来解决这个问题。但是,我希望 handleStuff 仍然使用最新值更新,因为 eventListner 已经在初始渲染中添加,并且在第二个 keydown 时它应该将 10 添加到 110 而不是 100,但它继续使用初始状态值 100反而。为什么每次都必须清除旧的侦听器并添加新的侦听器才能正常工作?

[value, setValue] = useState(100)

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

useEffect(() => {
  window.addEventListener('keydown', handleStuff)
  return () => {
    window.removeEventListener('keydown', handleStuff)
  }
 },[]);
Run Code Online (Sandbox Code Playgroud)

我对解决方案并不是很感兴趣,我真的很想了解 useEffect() 和 useState() 钩子在这种情况下是如何工作的。

Ale*_*lop 6

嘿, useEffect 钩子可能有点令人困惑。但想到它的方式是

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

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

useEffect(() => {
  // Called when x y & z updates
}, [x, y, z])
Run Code Online (Sandbox Code Playgroud)

问题是您没有在代码中监听 currentFocus 更新。

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

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

现在解释你的困惑:

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

当您在此处传递 currentFocus 时,唯一一次将 currentFocus 值传递给焦点 useState 是在第一次渲染上。所以你需要监听 currentFocus 更新,然后设置新的焦点,它应该如何工作!

// 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]);
Run Code Online (Sandbox Code Playgroud)

希望有帮助!