useState 在第二次点击时更新状态
Posted
技术标签:
【中文标题】useState 在第二次点击时更新状态【英文标题】:useState updates state on second click 【发布时间】:2021-10-28 05:02:48 【问题描述】:我已经看到这个问题以前被问过很多次,但没有一个答案对我来说有意义。在尝试了我能找到的所有解决方案之后,我决定自己问。
以下是我的代码,主要问题是在 DOM filteredData
中仅在第二次点击时发生变化。请注意,projs
是包含获取的数据的道具,这些数据会被过滤并显示
const langs = ["react", "next js", "material-ui", "tailwind css", "firebase"];
const [projectData, setProjectData] = useState([]);
const [filteredData, setFilteredData] = useState([]);
const [category, setCategory] = useState("");
useEffect(() =>
setProjectData(projs);
, []);
const handleCategory = (res) =>
setCategory(res.data);
const filter = projectData.filter((data) => data.category === category);
setFilteredData(filter);
;
按钮:
langs.map((data, index) => (
<button
key=index
class="px-2 sm:px-6 py-2 ring-2 font-semibold ring-portfBtnLight rounded-md transform hover:scale-110 transition duration-500"
onClick=() => handleCategory( data )
>
data
</button>
))
我现在很迷茫,任何帮助将不胜感激
【问题讨论】:
【参考方案1】:我认为这是问题
setCategory(res.data);
const filter = projectData.filter((data) => data.category === category);
您调用setCategory
。但这不会改变您在后续行中引用的 category
的直接值。
我想你想要这个:
const updatedCategory = res.data;
setCategory(updatedCategory);
const filter = projectData.filter((data) => data.category === updatedCategory);
另外,res.data
实际上是您想要使用的“类别”吗?我只是问,因为你在这么多变量、参数和对象成员之间使用data
,我不禁怀疑这是否真的是一个错字。
【讨论】:
是的res.data
绝对是该类别,因为它可以完美运行,但在第二次点击时。尝试了您的替代方案,问题仍然存在。
而“类别”是一个数字或字符串,对吗?如果是其他类型(数组或对象),那就另当别论了。【参考方案2】:
您不能在同一渲染周期中使用新设置的状态值。要在同一个处理程序中继续调用两个 setState
,您需要使用来自 res.data
的类别来生成新的过滤数组,然后设置两者。
const handleCategory = (res) =>
const filter = projectData.filter((data) => data.category === res.data);
setCategory(res.data);
setFilteredData(filter);
;
const useState, useEffect = React;
function App( projs )
const langs = ["react", "next js", "material-ui", "tailwind css", "firebase"];
const [projectData, setProjectData] = useState([]);
const [filteredData, setFilteredData] = useState([]);
const [category, setCategory] = useState("");
useEffect(() =>
setProjectData(projs);
, [projs]); // need to watch for change as props won't update this automatically. Setting state from props is somewhat of an anti-pattern
const handleCategory = (res) =>
const filter = projectData.filter((data) => data.category === res.data);
setCategory(res.data);
setFilteredData(filter);
;
return (
<div className="App">
langs.map((data) => (
<button
key=data // avoid using index as key as this will lead to erros in updating.
class=(data === category ? 'selected ' : '') + "px-2 sm:px-6 py-2 ring-2 font-semibold ring-portfBtnLight rounded-md transform hover:scale-110 transition duration-500"
onClick=() => handleCategory( data )
>
data
</button>
))
<div>
<h3>category</h3>
filteredData.length
? filteredData.map(p => (
<div>
<p>p.value – p.category</p>
</div>
))
: <p>No projects match</p>
</div>
</div>
);
const projectData = [ id: 1, value: 'Project 1', category: 'react' , id: 2, value: 'Project 2', category: 'next js' , id: 3, value: 'Project 3', category: 'react' , id: 4, value: 'Project 4', category: 'material-ui' ]
ReactDOM.render(
<App projs=projectData />,
document.getElementById("root")
);
.selected
background-color: tomato;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
或者,在 useEffect
中更新 filteredData
以监视对 category
或 projectData
的更改
useEffect(() =>
setFilteredData(projectData.filter((data) => data.category === category));
, [category, projectData]);
const handleCategory = (res) =>
setCategory(res.data);
;
const useState, useEffect = React;
function App( projs )
const langs = ["react", "next js", "material-ui", "tailwind css", "firebase"];
const [projectData, setProjectData] = useState([]);
const [filteredData, setFilteredData] = useState([]);
const [category, setCategory] = useState("");
useEffect(() =>
setProjectData(projs);
, [projs]); // need to watch for change as props won't update this automatically. Setting state from props is somewhat of an anti-pattern
useEffect(() =>
setFilteredData(projectData.filter((data) => data.category === category));
, [category, projectData]);
const handleCategory = (res) =>
setCategory(res.data);
;
return (
<div className="App">
langs.map((data) => (
<button
key=data
class=(data === category ? 'selected ' : '') + "px-2 sm:px-6 py-2 ring-2 font-semibold ring-portfBtnLight rounded-md transform hover:scale-110 transition duration-500"
onClick=() => handleCategory( data )
>
data
</button>
))
<div>
<h3>category</h3>
filteredData.length
? filteredData.map(p => (
<div>
<p>p.value – p.category</p>
</div>
))
: <p>No projects match</p>
</div>
</div>
);
const projectData = [ id: 1, value: 'Project 1', category: 'react' , id: 2, value: 'Project 2', category: 'next js' , id: 3, value: 'Project 3', category: 'react' , id: 4, value: 'Project 4', category: 'material-ui' ]
ReactDOM.render(
<App projs=projectData />,
document.getElementById("root")
);
.selected
background-color: tomato;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
如 sn-ps 中所述——
从 props 设置状态有点反模式,但如果你必须将 prop 添加到依赖数组中,以便在 prop 更改时更新状态。 (道具更改不会强制重新安装)。
另外,避免使用index
作为键,尤其是在映射顺序/成员身份将发生变化的数组时,因为 React 不会按预期更新。
【讨论】:
就是这样,谢谢!有道理,感谢index
/ 键的提示
@starbvuks - 哪个解决方案有效?因为建议的第一个解决方案似乎与我的相同。还是建议使用useEffect
或解决问题的关键/索引?
useEffect
建议以上是关于useState 在第二次点击时更新状态的主要内容,如果未能解决你的问题,请参考以下文章
使用 ref 从父函数组件传递时 useState 不更新数据
React Hooks:useState with onClick 仅更新第二次单击按钮?
我收到此错误:“来自 useState() 和 useReducer() Hooks 的状态更新不支持第二个回调...”当我更改状态时
React useState hook 使用初始状态值并忽略更新
为啥 setState 回调会抛出错误:“来自 useState() 和 useReducer() Hooks 的状态更新不支持第二个回调参数...”