调用 onClick 事件时,React 状态始终未定义

React state is always undefined when invoke onClick event

所以我有以下代码:

export default function Component() {  
  
  const [list, setList] = useState<JSX.Element[]>();
  const [active, setActive] = useState<JSX.Element>();


  useEffect(()=>{
    let startTab = <li key={"0000-0000-0000-0000"} onClick={() => onClick()}>Star 1</li>;
    let secondTab = <li key={"0001-0000-0000-0000"} onClick={() => onClick()}>Star 2</li>;

    setList(() => [startTab, secondTab]);
    setActive(() => startTab);
  },[])

  const onClick= () =>{
    console.log(list)
  }

  return (
    <div id="BodyMain" className={css["Body-container"]}>
      <div className={css["tab-header"]}>
        { (
          <ul className={css["navs"]}>
            {list?.map(tabItem => tabItem)}
          </ul>)
        }
      </div>
      <div className={css["tab-body"]}>{}</div>
    </div> 
  );
}

每次我调用 onClick 函数时它只是 returns 未定义!

然而,'React Developer Tools'表明这些状态确实具有价值!!

我无法更改 onClick 函数的状态,因为它始终未定义。我做错了什么?我该如何解决?

问题在于您使用 useEffect() 挂钩的方式。 当您没有任何依赖项时,该钩子将 运行 一次。因此 setList(() => [startTab, secondTab]);只需 运行 一次

如果想每次点击都更新,可以为useEffect() hook添加依赖:

const [list, setList] = useState<JSX.Element[]>();
const [active, setActive] = useState<JSX.Element>();
const [ count, setCount ] = useState (0);

useEffect(()=>{
  let startTab = <li key={"0000-0000-0000-0000"} onClick={() => onClick()}>Star 1</li>;
  let secondTab = <li key={"0001-0000-0000-0000"} onClick={() => onClick()}>Star 2</li>;

  setList(() => [startTab, secondTab]);
  setActive(() => startTab);
},[count])

const onClick= () =>{
  setCount(() => count+1)
  console.log(list)
}

我通常使用计数变量来捕获任何变化并将其设置为 useEffect 依赖项。

https://reactjs.org/docs/hooks-effect.html

阅读更多内容

发生这种情况是因为在第一次渲染期间 list 未定义。并且 useEffect 捕获列表未定义的 onClick 函数。由于 useEffect 运行s 仅一次 - onClick 内的列表将始终未定义。但是如果useEffect会运行, list 也会在 useEffect 中更新。正如@nam-h-nguyen所说,真正将count作为依赖项useEffect将重新运行,因此将捕获列表的新值。

实际上,还有另一种解决方案

 const [list, setList] = useState<JSX.Element[]>();
 const [active, setActive] = useState<JSX.Element>();
 const [ count, setCount ] = useState (0);
 let startTab = <li key={"0000-0000-0000-0000"} onClick={() => 
    onClick()}>Star 1</li>;
 let secondTab = <li key={"0001-0000-0000-0000"} onClick={() => 
    onClick()}>Star 2</li>;

 useEffect(()=>{
      setList(() => [startTab, secondTab]);
      setActive(() => startTab);
    },[])
  
 const onClick= () =>{
      setList(() => [startTab, secondTab]);
      console.log(list)
    }

我所做的是:

  • 我从 useEffect() 挂钩中取出了 startTab 和 seconTab,并将它们作为该组件的全局变量,以便我可以在该组件内的任何地方使用它们。
  • 然后,我只需要直接在 onClick() 函数中更新“列表”。
  • 并且我在第一次渲染期间使用了没有依赖项的 useEffect 来更新列表。

比起把所有东西都放在 useEffect hook() 中,我更喜欢这样做,因为你放在里面的任何东西都会成为它的局部变量,你不能在 useEffect() 钩子之外使用它。