[英]Updating state in async function
I'm very new to react so apologies if this question has already been answered or should be phrased differently.如果这个问题已经得到回答或应该以不同的方式表达,我很抱歉做出反应。 I have a functional component that fetches a.json file from my public folder in an async function (loadData()).
我有一个功能组件,它从我的公共文件夹中的异步 function (loadData()) 中获取 a.json 文件。 Using the developer tools in my chrome window, I can see that the function gets me exactly what I want, yet the state doesn't seem to want to update when I use setData.
使用我的 chrome window 中的开发人员工具,我可以看到 function 正是我想要的,但 state 在我使用 setData 时似乎不想更新。
Edit: So I think I know what the problem is, which is that the first time the component renders, the variable source
needs that JSON object which won't be there until the component re-renders.编辑:所以我想我知道问题出在哪里,即组件第一次渲染时,变量
source
需要 JSON object 在组件重新渲染之前不会存在。 If that's the case, should all the code starting at let source = pickRandomVerb(data)
go somewhere outside useEffect()?如果是这种情况,所有从
let source = pickRandomVerb(data)
go 开始的代码都应该在 useEffect() 之外的某个地方吗?
function ComposedTextField() {
const classes = useStyles();
const [data, setData] = React.useState([]);
const [displayVerb, setDisplayVerb] = React.useState('');
const pickRandomVerb = (list) => {
var obj_keys = Object.keys(list);
var ran_key = obj_keys[Math.floor(Math.random() * obj_keys.length)];
return list[ran_key];
}
const loadData = async() => {
const response = await fetch('verbs.json');
const json = await response.json();
setData(json);
console.log(json); //json is exactly what I want here
console.log(data); //data is just '[]' here
}
useEffect(() => {
loadData();
console.log(data) //data is also '[]' here
let source = pickRandomVerb(data)
let verbSource = source.infinitive;
let showVerb = verbSource.toString().replaceAll("\"", "");
setDisplayVerb(showVerb)
}, [])
return(
<div>
<Typography className = {classes.form}>
<p>{displayVerb}</p>
</Typography>
</div>
)
}
Can anyone let me know what I'm missing?谁能让我知道我错过了什么? Thanks in advance.
提前致谢。
setState is async also then you can't see the data changed in setState 也是异步的,那么您看不到数据已更改
const loadData = async() => {
const response = await fetch('verbs.json');
const json = await response.json();
setData(json);
console.log(json); //json is exactly what I want here
console.log(data); //data is just '[]' here
}
Your useEffect doesn't define the dependency then it just run once.您的 useEffect 没有定义依赖项,然后它只运行一次。 If you want to see your data changed just add dependency for data to track when data changed.
如果您想查看您的数据更改,只需添加数据依赖项以跟踪数据更改的时间。
/// Just load at the first time you render you component
useEffect(()=>{
loadData();
},[])
useEffect(() => {
console.log(data)
let source = pickRandomVerb(data)
let verbSource = source.infinitive;
let showVerb = verbSource.toString().replaceAll("\"", "");
setDisplayVerb(showVerb)
}, [data]) //Just add dependency here for useEffect
useState hook is also asynchronous, and will not be reflected immediately and this question already addressed link-1 , link-2 useState 钩子也是异步的,不会立即反映,这个问题已经解决了link-1 , link-2
changes required (you have to listen the changes of the data in useEffect),需要更改(您必须在 useEffect 中监听数据的更改),
useEffect(() => {
loadData();
console.log(data) //data is also '[]' here
}, []);
useEffect(() => {
let source = pickRandomVerb(data)
let verbSource = source.infinitive;
let showVerb = verbSource.toString().replaceAll("\"", "");
setDisplayVerb(showVerb)
}, [data]);
Maybe you can try something like this也许你可以尝试这样的事情
function ComposedTextField() {
const classes = useStyles();
const [data, setData] = React.useState([]);
const [displayVerb, setDisplayVerb] = React.useState('');
const pickRandomVerb = (list) => {
var obj_keys = Object.keys(list);
var ran_key = obj_keys[Math.floor(Math.random() * obj_keys.length)];
return list[ran_key];
}
const loadData = async() => {
const response = await fetch('verbs.json');
const json = await response.json();
setData(json);
console.log(json); //json is exactly what I want here
console.log(data); //data is just '[]' here
}
useEffect(() => {
loadData();
console.log(data) //data is also '[]' here
}, [])
// Move that code outside useEffect and inside condition
if(data!==[]){
let source = pickRandomVerb(data)
let verbSource = source.infinitive;
let showVerb = verbSource.toString().replaceAll("\"", "");
setDisplayVerb(showVerb)
}
return(
<div>
<Typography className = {classes.form}>
<p>{displayVerb}</p>
</Typography>
</div>
)
}
In this code setDisplayVerb() will be called when the data has some value.在此代码中,当数据具有某些值时,将调用 setDisplayVerb()。 The flow of the control would be something like this.
控制流程是这样的。
This way you should be able to see the data on your screen.这样,您应该能够在屏幕上看到数据。
so to expand on my comment, try this:所以要扩展我的评论,试试这个:
const loadData = async() => {
const response = await fetch('verbs.json');
const json = await response.json();
return json; /// <<< note: here you return data
}
useEffect(async () => {
const data = await loadData(); // <<<< note: here you wait for data
console.log(data);
let source = pickRandomVerb(data)
let verbSource = source.infinitive;
let showVerb = verbSource.toString().replaceAll("\"", "");
setDisplayVerb(showVerb)
}, [])
this will only get you the data on initial load.这只会让您获得初始加载的数据。
Just as a side note: to improve a bit on this component, you can move your loadData
function outside of the component.顺便说一句:要改进此组件,您可以将
loadData
function 移到组件之外。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.