Reactjs 同时使用多个“useState()”状态
我正在使用异步API调用获取父记录中的一些模板数据。(子组件将根据在其他子组件中所做的选择进行切换。) 模板数据非常大,所以我只想获取一次。此外,我试图只传递每个孩子所需的最小道具。有些只需要模板的名称,有些则需要适当的组数组。因此,我试图在父元素中完成这项工作。我似乎对设置状态有些困惑Reactjs 同时使用多个“useState()”状态,reactjs,async-await,react-hooks,Reactjs,Async Await,React Hooks,我正在使用异步API调用获取父记录中的一些模板数据。(子组件将根据在其他子组件中所做的选择进行切换。) 模板数据非常大,所以我只想获取一次。此外,我试图只传递每个孩子所需的最小道具。有些只需要模板的名称,有些则需要适当的组数组。因此,我试图在父元素中完成这项工作。我似乎对设置状态有些困惑 编辑 我正在调用useffect,没有参数,以便它在加载时执行。我希望第一个setTemplates()将设置templatesstate变量,以便我可以在下次调用setTemplateChoices()时使
编辑 我正在调用
useffect
,没有参数,以便它在加载时执行。我希望第一个setTemplates()
将设置templates
state变量,以便我可以在下次调用setTemplateChoices()
时使用它,同时设置templateChoices
状态
我甚至尝试将它们分成两个useEffect调用:
useEffect(() => {
setTemplates(defaultTemplates)
}, [])
useEffect(() => {
setTemplateChoices(templates.map(template => template.name))
}, [templates])
还是没有快乐。为什么不设置
模板选项?将默认设置置于使用状态:
import React, { useState, useEffect } from 'react'
export default function ParentComponent() {
const [templates, setTemplates] = useState([
{ id: 1, name: 'Form 1', }, // plus - groups: [ {}, {} ... ], etc.
{ id: 2, name: 'Form 2', }, // plus - groups: [ {}, {} ... ], etc.
{ id: 3, name: 'Form 3', }, // plus - groups: [ {}, {} ... ], etc.
])
const [templateChoices, setTemplateChoices] = useState([])
return (
<div>
<h2>Templates</h2>
{templates.map(template => (
<p>{template.name}</p>
))}
</div>
)
}
import React,{useState,useffect}来自“React”
导出默认函数ParentComponent(){
const[templates,setTemplates]=useState([
{id:1,名称:'form1',},//plus-groups:[{},{}…]等。
{id:2,名称:'form2',},//plus-groups:[{},{}…]等。
{id:3,名称:'form3',},//plus-groups:[{},{}…]等。
])
常量[templateChoices,setTemplateChoices]=useState([])
返回(
模板
{templates.map(模板=>(
{template.name}
))}
)
}
我假设您正在使用useffect
,因为您正在从其他地方加载数据,并且由于变量更改,查询中的某些因素可能需要自动刷新
如果没有,您应该直接设置状态(即useState(defaultQuery)或useState(()=>defaultQuery)
)。这将仅在组件加载时调用它一次
第一个示例不起作用的原因是模板没有立即更新。它需要刷新。您可以使用useEffect两次,但效率很低。更容易的解决办法是
useEffect(() => {
setTemplates(defaultTemplates);
setTemplateChoices(defaultTemplates.map(template => template.name));
}, [defaultTemplates]);
对于其他人来说,将它们分成两个useffect调用实际上是可行的:
useEffect(() => {
setTemplates(defaultTemplates)
}, [])
useEffect(() => {
setTemplateChoices(templates.map(template => template.name))
}, [templates])
下面是我如何使用React实现这一点的:仅使用1个useffect
和其中的两个setState
调用
PS:我没有使用async,因为代码段不太支持它。但是你可以用它
函数mockAPI(){
const defaultTemplates=[
{id:1,名称:'Form 1'},
{id:2,名称:'form2'},
{id:3,名称:'Form 3'},
];
返回新承诺((解决、拒绝)=>{
setTimeout(()=>resolve(defaultTemplates),1000);
});
}
函数App(){
const[templates,setTemplates]=React.useState(null);
const[templateChoices,setTemplateChoices]=React.useState([]);
log(“渲染应用程序…”);
console.log(“模板:”+模板);
log(“templateChoices:+templateChoices”);
React.useffect(()=>{
log(“运行useffect…”);
如果(!模板){
log(“获取模板…”);
mockAPI()。然后((结果)=>setTemplates(结果));
}
否则{
log(“设置模板选项…”);
setTemplateChoices(templates.map(template=>template.name));
}
},[模板];
const choiceItems=templateChoices.map((选项,索引)=>
{choice}
);
返回(
模板?
模板选择?
{choiceItems}
:null
:正在加载模板。。。
);
}
render(,document.getElementById(“根”))代码>
您与分离的useffect()共享的解决方案在我这方面运行良好。
s您需要提供更多信息,您使用两个单独的useffect的第二个解决方案似乎是合理的,应该可以工作-到底什么似乎不起作用?问题是,setTemplates()
确实似乎在执行useEffect时设置了模板,我不能立即在调用setTemplateChoices()时使用templates
state变量(
:-)(我为浪费大家的时间而道歉。一个血淋淋的额头和一张被毁的桌子…后来证明,是的,这两个独立的useEffect()
呼叫工作得很好-但我发誓,在我尝试呼叫的前4次呼叫中,它们都没有。我现在正在筛选提交,看看我哪里出错了。再次抱歉。
import React, { useState, useEffect } from 'react'
export default function ParentComponent() {
const [templates, setTemplates] = useState([
{ id: 1, name: 'Form 1', }, // plus - groups: [ {}, {} ... ], etc.
{ id: 2, name: 'Form 2', }, // plus - groups: [ {}, {} ... ], etc.
{ id: 3, name: 'Form 3', }, // plus - groups: [ {}, {} ... ], etc.
])
const [templateChoices, setTemplateChoices] = useState([])
return (
<div>
<h2>Templates</h2>
{templates.map(template => (
<p>{template.name}</p>
))}
</div>
)
}
useEffect(() => {
setTemplates(defaultTemplates);
setTemplateChoices(defaultTemplates.map(template => template.name));
}, [defaultTemplates]);
useEffect(() => {
setTemplates(defaultTemplates)
}, [])
useEffect(() => {
setTemplateChoices(templates.map(template => template.name))
}, [templates])