【问题标题】:Why when the state is updated the changes in the rendering are not updated?为什么当状态更新时渲染中的变化没有更新?
【发布时间】:2020-09-03 20:23:20
【问题描述】:

我创建了一个挂钩来访问数据库及其方法的集合。

import { remote } from 'electron'
import { useState, useEffect } from "react"

function useCollections(collections = []) {

    let [dbInstances, setDbInstances] = useState(null)
    let [data, setData] = useState(null)

    // DB METHODS

    // Create
    let create = async (doc, dbName) => {
        await dbInstances[dbName].create(doc)
        let newData = await dbInstances[dbName].readAll()
        setData({ ...data, [dbName]: newData })
    }

    // Get details
    let getDetails = async (id, dbName) => {
        let doc = await dbInstances[dbName].read(id)
        return doc
    }

    // Delete
    let deleteOne = async (id, dbName) => {
         await dbInstances[dbName].deleteOne(id)
         let newData = await dbInstances[dbName].readAll()
         setData({ ...data, [dbName]: newData })
    }

    // Update
    let updateOne = async (id, updatedDoc, dbName) => {
        await dbInstances[dbName].archive(id, updatedDoc)
        let newData = await dbInstances[dbName].readAll()
        setData({ ...data, [dbName]: newData })
    }

    // EFFECTS
   
    useEffect(() => {
        console.log('mounting component')
        let newDBIs = {}
        collections.forEach(col => newDBIs[col] = remote.getGlobal(col))
        console.log('db instances settted', newDBIs)
        setDbInstances(newDBIs)
    }, [])

    // When DBs are instantiated, request all docs and set data with response
    useEffect(() => {
        if (
            dbInstances !== null &&
            data === null &&
            Object.keys(dbInstances).length === collections.length) 
        {
                console.log('setting data')
                let newData = {}
                collections.forEach(async col => newData[col] = await dbInstances[col].readAll())
                console.log('data setted => ', newData)
                setData(newData)
        }
    }, [dbInstances])

    return {
        data,
        create,
        getDetails,
        deleteOne,
        updateOne
    };
}

export default useCollections;

在消费钩子返回的数据的组件中,即使变量data包含预期的数据,这些也不会被渲染。

import WindowsLayout from "../../components/layout/WindowsLayout"
import { useState, useEffect } from "react"
import { remote } from "electron"
import useCollections from "../../hooks/useCollections"

const EditWorkWindow = ({ workId }) => {

    let { data, deleteOne, updateOne } = useCollections([
        'workDB',
        'studioDB',
        'rateDB'
    ])

    useEffect(() => {
        if (data !== null) console.log(data)
    }, [data])

   
    return (
        <WindowsLayout title="Edit work window">
            <div style={{ height: 243 }} className="window-content">
                <div className="padded-more bg-gray-200">
                   <h2>{JSON.stringify(data)}</h2>
                   <button onClick={() => console.log(data)}>CLG</button>          
                </div>
            </div>
        </WindowsLayout >
    )
}

export default EditWorkWindow

效果挂钩通过控制台显示预期的数据。

&lt;h2&gt;{JSON.stringify(data)}&lt;/h2&gt; = {}

当按钮被点击时,预期的数据会显示在控制台上。

我不明白为什么如果数据包含属性,它们不会显示在{JSON.stringify(data)}

这是点击按钮后控制台显示的内容 console.log(data) image

这是示例 data 及其属性

{
   "workDB":[
      {
         "product":"Work name 1",
         "amounts_rates":[
            {
               "rate":"EflcQflqu2oWWVk2",
               "amount":6
            },
            {
               "rate":"FeMIX00pwpmZwoVW",
               "amount":1
            }
         ],
         "date":"2020-08-31",
         "studio":"BCvPeWzMiS8fZsmS",
         "_id":"2ZvHMWFODBHYWEBo",
         "createdAt":"2020-08-31T09:39:21.077Z",
         "updatedAt":"2020-08-31T09:39:21.077Z"
      },
      {
         "product":"Work name 2",
         "amounts_rates":[
            
         ],
         "date":"2020-09-02",
         "director":"",
         "_id":"PRpp1OQcJnkFKeR0",
         "createdAt":"2020-09-01T19:56:33.201Z",
         "updatedAt":"2020-09-01T19:56:33.201Z"
      }
   ],
   "studioDB":[
      {
         "name":"Studio name 1",
         "_id":"0J1AVXtgDjwBjRS9",
         "createdAt":"2020-08-25T10:18:40.004Z",
         "updatedAt":"2020-08-25T10:18:40.004Z"
      },
      {
         "name":"Studio name 2",
         "_id":"8sFH7gncaM6V7lHh",
         "createdAt":"2020-08-25T10:19:45.232Z",
         "updatedAt":"2020-08-25T10:19:45.232Z"
      }
   ],
   "rateDB":[
      {
         "name":"Rate name 1",
         "value":4.1,
         "_id":"EflcQflqu2oWWVk2",
         "createdAt":"2020-08-25T10:24:17.357Z",
         "updatedAt":"2020-08-25T10:24:17.357Z"
      },
      {
         "name":"Rate name 1",
         "value":34,
         "_id":"FeMIX00pwpmZwoVW",
         "createdAt":"2020-08-25T10:24:25.628Z",
         "updatedAt":"2020-08-25T10:24:25.628Z"
      }
   ]
}

【问题讨论】:

  • 你能举例说明data 在你记录它时所包含的内容吗?是否有可能它是一个继承的对象,现在具有“自己的”属性但只有超类有?或者它所拥有的不是 JSON 可序列化的
  • 感谢您的评论 casraf ,我已经编辑了问题并添加了带有 console.log(data) 返回的图像

标签: reactjs electron next.js


【解决方案1】:

这是异步问题。

// When DBs are instantiated, request all docs and set data with response
    useEffect(() => {
        if (
            dbInstances !== null &&
            data === null &&
            Object.keys(dbInstances).length === collections.length) 
        {
                console.log('setting data')
                let newData = {}
                collections.forEach(async col => newData[col] = await dbInstances[col].readAll())
                console.log('data setted => ', newData)

                setData(newData) // <-- ?LOOK HERE

        }
    }, [dbInstances])

所以你let newData = {} 为空对象,并通过调用setData() 将其发送出去以触发更新重新渲染,但newData 在调用时为空。

在您的渲染函数JSON.stringify(data) 中获取数据,但在渲染时它仍然是空的!

只有当async col =&gt; newData[col] = await someValue 调用被解决时,你的newData属性 才会被分配新的值,newData 对象保持不变。但是当它解决的时候,渲染已经完成了。

解决方法:等到异步函数调用解决后,再调用setData()

useEffect(() => {
    // ...
    const promises = collections.map(async col => {
        newData[col] = await dbInstances[col].readAll())
    })
    Promise.all(promises).then(() => { setData(newData) })
})

您在控制台中检查时看到更新值的原因是您没有“足够快”地检查。当您在控制台中单击鼠标展开对象时,它的属性已经被赋值。但是如果你改变了

console.log('data setted => ', newData) 
// to
console.log('data setted => ', JSON.stringify(newData))

你会看到一个空的对象。

【讨论】:

  • 很好的答案!解释的很好,解决了我的问题。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2021-01-27
  • 2020-11-04
  • 2021-07-11
  • 2020-06-21
  • 2017-03-25
  • 2023-01-28
  • 1970-01-01
  • 2021-08-04
相关资源
最近更新 更多