React hooks 状态不使用最新的
React hooks state not using latest
我有下面的代码,我想在其中创建标签列表。在此示例中,我在 setAllTags()
中获取标签列表,然后在 setAvailableTags()
.
中获取一些可用标签
然后我遇到的问题是,当 setAvailableTags()
为 运行 时,它将删除在 setAllTags()
中获取的标签。当 setAvailableTags()
设置它的状态时,我在 setAllTags()
中设置的状态似乎没有被使用。
知道我能做些什么来解决这个问题吗?
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"));
控制台使用
登录
setting all tags to Object {all: Array[3], available: Array[0]}
setting available tags to Object {all: Array[0], available: Array[2]}
setTags
改变了内部反应状态而不是直接改变 tags
的值。所以直到下一次渲染它才会更新。
改为使用此调用:
setTags(currentTags => ({...currentTags, all}));
对 available
做同样的事情。
来自:https://reactjs.org/docs/hooks-reference.html#usestate
Unlike the setState method found in class components, useState does not automatically merge update objects. You can replicate this behavior by combining the function updater form with object spread syntax:
setState(prevState => {
// Object.assign would also work
return {...prevState, ...updatedValues};
});
Another option is useReducer, which is more suited for managing state objects that contain multiple sub-values.
如果你想 setAvailableTags()
基于 setAllTags()
你应该这样做
useEffect(setAvailableTags, [tags.all])
问题在于,当您将 Effect 与第二个参数 [] 一起使用时,该函数只会在第一次渲染组件时被调用。但是因为你在其中使用了 setState 组件被重新渲染,但是 useEffect 没有被调用,所以它不会正确更新。解决问题的一种方法是不在每个函数中使用 setState,而是 return 将数据发送到另一个函数,然后像这样设置状态。
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"];
return all;
};
const setAvailableTags = () => {
const available = ["tag 1", "tag 2"];
return available;
};
useEffect(() => {
const all = setAllTags();
const available = setAvailableTags();
setTags({
all: all,
available: available
});
}, []);
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>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
如果您需要从 API.
中获取数据,您可以使用 Promise.all()
在 React 文档中,您可以看到 useEffect
是如何工作的 (https://reactjs.org/docs/hooks-effect.html)
Experienced JavaScript developers might notice that the function passed to useEffect is going to be different on every render. This is intentional. In fact, this is what lets us read the count value from inside the effect without worrying about it getting stale. Every time we re-render, we schedule a different effect, replacing the previous one. In a way, this makes the effects behave more like a part of the render result — each effect “belongs” to a particular render. We will see more clearly why this is useful later on this page.
这意味着渲染函数中的每个副作用只能访问 useState
的初始结果。请记住,React 状态是不可变的,因此更新状态然后尝试在同一渲染周期内使用更新的版本是没有意义的。
您只需调用即可看到:
setTags({ all: ['test'] })
console.log(tags)
您应该注意到 tags
根本没有改变。
我个人会在这里使用钩子约定,并将您的 useState 分成两个单独的变量:
const [allTags, setAllTags] = useState([])
const [availableTags, setAvailableTags] = useState([])
这使您的效果更加明确(因为它们只需要更新一个变量),并提高了可读性。
对于初始渲染,您的 tags
是
{
all: [],
availableTags:[]
}
因此,对于 useEffect
两个函数,更新此初始对象。
并且您的 useEffect
函数不会在状态更新时被调用。
您可以像下面这样使用它们:
const setAvailableTags = () => {
const available = ["tag 1", "tag 2"];
setTags(prevTags => ({...prevTags, available}));
};
useEffect(setAllTags, []);
useEffect(setAvailableTags, [tags.all]);
我有下面的代码,我想在其中创建标签列表。在此示例中,我在 setAllTags()
中获取标签列表,然后在 setAvailableTags()
.
然后我遇到的问题是,当 setAvailableTags()
为 运行 时,它将删除在 setAllTags()
中获取的标签。当 setAvailableTags()
设置它的状态时,我在 setAllTags()
中设置的状态似乎没有被使用。
知道我能做些什么来解决这个问题吗?
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"));
控制台使用
登录setting all tags to Object {all: Array[3], available: Array[0]}
setting available tags to Object {all: Array[0], available: Array[2]}
setTags
改变了内部反应状态而不是直接改变 tags
的值。所以直到下一次渲染它才会更新。
改为使用此调用:
setTags(currentTags => ({...currentTags, all}));
对 available
做同样的事情。
来自:https://reactjs.org/docs/hooks-reference.html#usestate
Unlike the setState method found in class components, useState does not automatically merge update objects. You can replicate this behavior by combining the function updater form with object spread syntax:
setState(prevState => {
// Object.assign would also work
return {...prevState, ...updatedValues};
});
Another option is useReducer, which is more suited for managing state objects that contain multiple sub-values.
如果你想 setAvailableTags()
基于 setAllTags()
你应该这样做
useEffect(setAvailableTags, [tags.all])
问题在于,当您将 Effect 与第二个参数 [] 一起使用时,该函数只会在第一次渲染组件时被调用。但是因为你在其中使用了 setState 组件被重新渲染,但是 useEffect 没有被调用,所以它不会正确更新。解决问题的一种方法是不在每个函数中使用 setState,而是 return 将数据发送到另一个函数,然后像这样设置状态。
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"];
return all;
};
const setAvailableTags = () => {
const available = ["tag 1", "tag 2"];
return available;
};
useEffect(() => {
const all = setAllTags();
const available = setAvailableTags();
setTags({
all: all,
available: available
});
}, []);
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>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
如果您需要从 API.
中获取数据,您可以使用 Promise.all()在 React 文档中,您可以看到 useEffect
是如何工作的 (https://reactjs.org/docs/hooks-effect.html)
Experienced JavaScript developers might notice that the function passed to useEffect is going to be different on every render. This is intentional. In fact, this is what lets us read the count value from inside the effect without worrying about it getting stale. Every time we re-render, we schedule a different effect, replacing the previous one. In a way, this makes the effects behave more like a part of the render result — each effect “belongs” to a particular render. We will see more clearly why this is useful later on this page.
这意味着渲染函数中的每个副作用只能访问 useState
的初始结果。请记住,React 状态是不可变的,因此更新状态然后尝试在同一渲染周期内使用更新的版本是没有意义的。
您只需调用即可看到:
setTags({ all: ['test'] })
console.log(tags)
您应该注意到 tags
根本没有改变。
我个人会在这里使用钩子约定,并将您的 useState 分成两个单独的变量:
const [allTags, setAllTags] = useState([])
const [availableTags, setAvailableTags] = useState([])
这使您的效果更加明确(因为它们只需要更新一个变量),并提高了可读性。
对于初始渲染,您的 tags
是
{
all: [],
availableTags:[]
}
因此,对于 useEffect
两个函数,更新此初始对象。
并且您的 useEffect
函数不会在状态更新时被调用。
您可以像下面这样使用它们:
const setAvailableTags = () => {
const available = ["tag 1", "tag 2"];
setTags(prevTags => ({...prevTags, available}));
};
useEffect(setAllTags, []);
useEffect(setAvailableTags, [tags.all]);