【问题标题】:State only set on second render (react-native)仅在第二次渲染时设置状态(react-native)
【发布时间】:2021-04-30 20:15:50
【问题描述】:

我正在从 Realm 文件数据库中提取数据,但数据似乎只出现在第二次渲染中。这是我的代码:

import React, { useState, useEffect } from 'react'
import {getAllArchive} from '../Schemas/activitiesArchiveSchema';

const Stats = () => {
  const [Archives, setArchives] = useState();

  useEffect(() => {
    (async () => setArchives(await getAllArchive()))();
    console.log(JSON.stringify(Archives))
  }, []);

数据库功能:

export const getAllArchive = () => {
    return new Promise((resolve, reject) => {
        Realm.open(databaseOptions).then(realm => {
            let activitiesList = realm.objects(ARCHIVE_LIST_SCHEMA)
            resolve(activitiesList)
        }).catch((error) => reject(error))
    })
}

输出:

 LOG  undefined
 LOG  {"0":{"title":"sw2","records":{"0":{"date":"4/28/2021","seconds":7,"minutes":0,"hours":1},"1":{"date":"4/27/2021","seconds":7,"minutes":0,"hours":0},"2":{"date":"4/28/2021","seconds":7,"minutes":0,"hours":0}}},"1":{"title":"jj","records":{"0":{"date":"4/25/2021","seconds":0,"minutes":55,"hours":1}}},"2":{"title":"l,kl","records":{"0":{"date":"4/28/2021","seconds":4,"minutes":12,"hours":1}}},"3":{"title":"fsdfdsf","records":{"0":{"date":"4/25/2021","seconds":4,"minutes":43,"hours":1}}},"4":{"title":"sideProj","records":{"0":{"date":"4/26/2021","seconds":30,"minutes":29,"hours":1},"1":{"date":"4/27/2021","seconds":15,"minutes":18,"hours":1}}},"5":{"title":"work","records":{"0":{"date":"4/28/2021","seconds":36,"minutes":13,"hours":0},"1":{"date":"4/28/2021","seconds":37,"minutes":11,"hours":3}}},"6":{"title":"plp","records":{"0":{"date":"4/25/2021","seconds":2,"minutes":12,"hours":3}}},"7":{"title":"fff","records":{"0":{"date":"4/25/2021","seconds":3,"minutes":10,"hours":2}}},"8":{"title":"Work","records":{"0":{"date":"4/27/2021","seconds":1,"minutes":0,"hours":0}}},"9":{"title":"chilling","records":{"0":{"date":"4/27/2021","seconds":40,"minutes":4,"hours":3},"1":{"date":"4/27/2021","seconds":0,"minutes":0,"hours":0}}}}

有人可以指出代码中的任何问题吗?谢谢

【问题讨论】:

    标签: javascript reactjs react-native react-hooks realm


    【解决方案1】:

    您的数据没有在组件的第一次渲染中加载,这并不奇怪。 首先,让我们看看useEffect 在不提供任何依赖项的情况下会做什么——它会在每次重新渲染时执行。

    在这行代码上:

    (async () => setArchives(await getAllArchive()))();
    

    您正在获取异步数据,执行不会在此处暂停。所以,console.log(JSON.stringify(Archives)) 将被执行。如果Archived 仍然是undefined(意味着数据获取不完整),您会看到LOG undefined。当异步数据获取完成并更新状态时,导致组件重新渲染的原因因此再次调用useEffect,您会看到

    LOG  {"0":{"title":"sw2","records":{"0":{"date":"4/28/2021","seconds":7,"minutes":0,"hours":1},"1":{"date":"4/27/2021","seconds":7,"minutes":0,"hours":0},"2":{"date":"4/28/2021","seconds":7,"minutes":0,"hours":0}}},"1":{"title":"jj","records":{"0":{"date":"4/25/2021","seconds":0,"minutes":55,"hours":1}}},"2":{"title":"l,kl","records":{"0":{"date":"4/28/2021","seconds":4,"minutes":12,"hours":1}}},"3":{"title":"fsdfdsf","records":{"0":{"date":"4/25/2021","seconds":4,"minutes":43,"hours":1}}},"4":{"title":"sideProj","records":{"0":{"date":"4/26/2021","seconds":30,"minutes":29,"hours":1},"1":{"date":"4/27/2021","seconds":15,"minutes":18,"hours":1}}},"5":{"title":"work","records":{"0":{"date":"4/28/2021","seconds":36,"minutes":13,"hours":0},"1":{"date":"4/28/2021","seconds":37,"minutes":11,"hours":3}}},"6":{"title":"plp","records":{"0":{"date":"4/25/2021","seconds":2,"minutes":12,"hours":3}}},"7":{"title":"fff","records":{"0":{"date":"4/25/2021","seconds":3,"minutes":10,"hours":2}}},"8":{"title":"Work","records":{"0":{"date":"4/27/2021","seconds":1,"minutes":0,"hours":0}}},"9":{"title":"chilling","records":{"0":{"date":"4/27/2021","seconds":40,"minutes":4,"hours":3},"1":{"date":"4/27/2021","seconds":0,"minutes":0,"hours":0}}}}
    

    【讨论】:

    • 没错,正如您在我的评论中看到的那样,我最终在依赖数组中添加了一个具有该状态的单独 useEffect 。谢谢
    【解决方案2】:

    不就是你的console.log在setArchives之前发生了吗?尝试强制您的日志等待异步返回以对其进行测试。

    【讨论】:

    • 我试过 (async () => setArchives(await getAllArchive()))().then(()=>console.log(JSON.stringify(Archives)));` 如果那是什么你的意思是,但没有工作。我以为 await 会在运行日志之前等待,对吗?
    【解决方案3】:

    我很确定你不能在这里异步 setState:

    (async () => setArchives(await getAllArchive()))(); setState 不是异步 api,是吗? 试试:

    useEffect(() => {
      (async () => {
        const data = await getAllArchive();// async fetch data and store it in variable
    
        console.log(JSON.stringify(data, null, 2)); //log your response
    
        if(data){
    
          setArchives(data) //if success, then set state
    
        }else{
          console.log('could not fetch data') //if fail, resolve error somehow
        }
      }
      )();
      
    }, []);
    

    【讨论】:

    • 好点!所以你的代码有效。但是,仅在打印 data var 而非 Archives 状态时。您将如何让 setState 实际更新档案。我跑了`console.log(JSON.stringify(Archives)); ` 在setArchives (data) 之后,但仍未定义。
    • 当然是未定义的,因为在useEffect函数运行的那一刻,状态保持不变,这里打个比方:如果你在酒吧要酒,你需要等待调酒师修复你一个,当他们做对的时候,它不会神奇地出现在你面前吗?因此,对于状态,您的函数实际上需要完成运行才能访问更新的状态。如果你真的想在每次更新和每次渲染时检查你的状态,你可以在 useEffect 之后(外部)放置控制台日志。
    • 好吧,我正在尝试从另一个 useEffect 或 JSX 访问状态,但在第一次渲染中仍未定义。
    • 因为在第一次渲染时什么都没有......您正在等待获取数据,当它被获取时更新状态并渲染。这就是为什么发明了加载指示器和启动屏幕的原因。您的问题开始成为前端开发的非常基本的概念,我建议您实际阅读 React 文档。 reactjs.org/docs/…
    • 感谢您的意见,安德里斯。请查看我的评论以了解我的发现。
    【解决方案4】:

    我是新手,所以我希望我的代码在第一次渲染时等待并更新状态。但是,它预计在第一次渲染时没有价值,处理它的方法基本上是在另一个 useEffect 钩子中运行依赖代码,该钩子在其依赖项数组中具有该状态。代码如下:

    import React, { useState, useEffect } from 'react'
    import {getAllArchive} from '../Schemas/activitiesArchiveSchema';
    
    const Stats = () => {
      const [Archives, setArchives] = useState();
    
      useEffect(() => {
        (async () => setArchives(await getAllArchive()))();
      }, []);
    
      useEffect(() => {
        // "dependent code"
        console.log(JSON.stringify(Archives))
      }, [Archives])
    
    

    显然第一个渲染是未定义的,但第二个应该有值变化。

    谢谢

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-18
      • 1970-01-01
      • 2019-11-25
      • 1970-01-01
      • 2017-10-22
      • 2021-01-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多