反应挂钩状态不使用最新

nbo*_*bon 5 javascript reactjs react-hooks

我在下面的代码中想要创建标签列表。在此示例中,我获取的标签列表,setAllTags()然后获取中的多个可用标签setAvailableTags()

然后我setAvailableTags()遇到的问题是,当运行时它将删除在中获取的标签setAllTags()。似乎在设置状态setAllTags()时不使用我设置setAvailableTags()的状态。

知道我该如何解决吗?

https://codesandbox.io/s/rj40lz6554

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

const Search = () => {
  const [tags, setTags] = useState({
    all: [],
    available: []
  });

  const setAllTags = () => {
    const all = ["tag 1", "tag 2", "tag 3"];
    const newValue = {
      ...tags,
      all
    };
    console.log("setting all tags to ", newValue);
    setTags(newValue);
  };

  const setAvailableTags = () => {
    const available = ["tag 1", "tag 2"];
    const newValue = {
      ...tags,
      available
    };
    console.log("setting available tags to", newValue);
    setTags(newValue);
  };

  useEffect(setAllTags, []);
  useEffect(setAvailableTags, []);

  return (
    <div>
      <div>
        <select placeholder="Tags">
          {tags.all.map((tag, i) => (
            <option key={tag + i} value={tag}>
              {tag}
            </option>
          ))}
        </select>
      </div>
    </div>
  );
};

const App = () => {
  return (
    <div>
      <h1>Hello React!</h1>
      <Search />
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("app"));
Run Code Online (Sandbox Code Playgroud)

控制台记录有

setting all tags to Object {all: Array[3], available: Array[0]}
setting available tags to Object {all: Array[0], available: Array[2]}
Run Code Online (Sandbox Code Playgroud)

Uji*_*T34 5

setTags改变内部反应状态并且不直接改变 的值tags。所以直到下一次渲染它才会更新。

请改用此调用:

setTags(currentTags => ({...currentTags, all}));
Run Code Online (Sandbox Code Playgroud)

并对 执行同样的操作available


Mat*_*Way 3

在react文档中,您可以看到如何useEffect工作(https://reactjs.org/docs/hooks-effect.html

\n\n
\n

经验丰富的 JavaScript 开发人员可能会注意到,传递给 useEffect 的函数在每次渲染时都会有所不同。这是故意的。事实上,这让我们可以从效果内部读取计数值,而不必担心它会过时。每次重新渲染时,我们都会安排不同的效果,替换之前的效果。在某种程度上,这使得效果的行为更像渲染结果 \xe2\x80\x94 的一部分,每个效果 \xe2\x80\x9c 属于 \xe2\x80\x9d 到特定渲染。我们将在本页后面更清楚地看到为什么这很有用。

\n
\n\n

这意味着渲染函数中的每个副作用只能访问useState. 请记住,反应状态是不可变的,因此更新状态然后尝试在同一渲染周期内使用更新的版本是没有意义的。

\n\n

您只需调用以下命令即可看到这一点:

\n\n
setTags({ all: [\'test\'] })\nconsole.log(tags)\n
Run Code Online (Sandbox Code Playgroud)\n\n

您应该注意到这tags根本没有改变。

\n\n

就我个人而言,我会在这里使用钩子约定,并将 useState 分成两个单独的变量:

\n\n
const [allTags, setAllTags] = useState([])\nconst [availableTags, setAvailableTags] = useState([])\n
Run Code Online (Sandbox Code Playgroud)\n\n

这使您的效果更加明确(因为它们只需要更新一个变量),并提高可读性。

\n