关于useState当初始状态为对象时,更新数据出现的问题

user_tYDk6iCh
  • 51

我想同时展示一组数据name、sex、school,创建了一个useState hook,然后在getName、getSex、getSchool三次请求中依次给name、sex、school赋值,但是最后页面显示的结果只有sex有数据,其他全部是0,我想是setData中使用...data时重新覆盖了之前已经赋好的值,不过我不知道怎么改比较好,难道要分别写三个useState吗?

    const [data, setData] = useState<dataType>({
        name: 0,
        sex: 0,
        school: 0,
    });
const queryData = (params:any) => {

    // name
    getName(params).then(res =>{
        setData({ ...data, name: res.result.name })
    })

    // sex
    getSex(params).then(res =>{
        setData({ ...data, name: res.result.sex })
    })

    // school
    getSchool(params).then(res =>{
        setData({ ...data, name: res.result.school })
    })
}

useEffect(() => {
    let myparam  ........
    queryData(myparam)
},[])
回复
阅读 412
3 个回答

函数组件每一次重渲染都会重新执行函数体,每一次的 queryData 都会被重新创建,都不是原来的那个。而调用 queryData 的 effect 用 [] 作为依赖,只会在第一次渲染时创建,也就是说 effect 中的 queryData 属于第一次渲染时的函数作用域,queryData 中使用到 data 也是第一次渲染时的 data,你可以理解为 effect 产生了一个闭包,按这样的写法 queryData 中用到的 data 永远都是最初的那个。这也是 useEffect 中需要写足依赖的原因。

官方文档对 useEffect 的依赖注意事项有详细的描述
https://zh-hans.reactjs.org/d...
https://zh-hans.reactjs.org/d...

如果是想只在 Mount 完成时发请求,可以使用 setData(prevData => {...prevData, name: res.result.name}) 回调函数的方式来写。其他答案把三个请求合并成一个 Promise 能减少重渲染次数,感觉是可参考的优化。

1、想楼上说的使用promise.all 合并请求
2、如果有特殊情况不使用 Promise 合并结果一起渲染的,分开渲染的也可以试下添加多一个对象存储

const queryData = (params:any) => {
    const data2 = {...data}
    // name
    getName(params).then(res =>{
        data2.name = res.result.name
        setData({ ...data2 })
    })

    // sex
    getSex(params).then(res =>{
        data2.sex = res.result.sex 
        setData({ ...data, name: res.result.sex })
    })

    // school
    getSchool(params).then(res =>{
        data2.school  = res.result.school  
        setData({ ...data2 })
    })
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
你知道吗?

宣传栏