useContext 未在子组件中显示更新的状态(当从全局文件中的 useEffect 挂钩中的 firebase 检索数据时)

Posted

技术标签:

【中文标题】useContext 未在子组件中显示更新的状态(当从全局文件中的 useEffect 挂钩中的 firebase 检索数据时)【英文标题】:useContext is not displaying the updated state (when data is retrieved from firebase in useEffect hook in global file) in child component 【发布时间】:2021-02-17 21:50:47 【问题描述】:

我正在使用上下文 api 来获得产品的全局状态,为此我有 ProductsContext.js

我在 ProductsContext.js 中有一个像这样定义的空数组状态

const [products, setProducts] = useState([]);

在同一个文件 (ProductsContext.js) 中,我使用 useEffect 从 firebase 检索所有产品,然后更新产品状态。下面是 ProductsContext.js 的全部代码

import React,  createContext, useState, useEffect  from 'react'
import  db  from '../Config/Config'

export const ProductsContext = createContext();

export const ProductsContextProvider = (props) => 
    // console.log(props);
    const [products, setProducts] = useState([]);

    useEffect(() => 
        // console.log('use effect');
        const prevProducts = products;
        db.collection('Products').onSnapshot(snapshot => 
            let changes = snapshot.docChanges();
            changes.forEach(change => 
                if (change.type === 'added') 
                    prevProducts.push(
                        ProductID: change.doc.id,
                        ProductName: change.doc.data().ProductName,
                        ProductDescription: change.doc.data().ProductDescription,
                        ProductPrice: change.doc.data().ProductPrice,
                        ProductImg: change.doc.data().ProductImg
                    )
                
                // console.log(prevProducts);
                setProducts(prevProducts);
                console.log(products); // I am able to see the products in console
            )
        )
    )

    return (
        <ProductsContext.Provider value= products: [...products] >
            props.children
        </ProductsContext.Provider>
    )

我的问题是 Home.js 是我的子组件,我在这个文件中使用 useContext 但它没有返回更新的状态,而只返回一个空数组

import React,  useContext  from 'react'
import  ProductsContext  from '../Global/ProductsContext'

export const Home = () => 
    const  products  = useContext(ProductsContext);
    console.log(products); // empty array
    return (
        <div>

        </div>
    )

这是我的 app.js

import React,  Component  from 'react'
import  ProductsContextProvider  from './Global/ProductsContext'
import  Home  from './Components/Home'

export class App extends Component 
    render() 
        return (
            <ProductsContextProvider>
                <Home />
            </ProductsContextProvider>
        )
    


export default App

【问题讨论】:

setProducts(prevProducts); 正在设置本地状态...您在哪里将其存储到您的上下文中?...因为您使用空白 export const ProductsContext = createContext(); 创建了上下文并且没有更新上下文...这是为什么当你做const products = useContext(ProductsContext);时你会空白 如何更新上下文? ***.com/questions/50502664 先生,请检查我的以下答案 【参考方案1】:

只要你的状态是一个对象(或一个数组,但从技术上讲它也是一个对象),你必须避免改变它。

在您的代码中,您通过在原始数组上调用 push(...) 而不是创建它的副本来改变您的 products 数组。

使用变异数组设置状态不会触发更新,因为 React 会将下一个数组的引用与前一个数组的引用进行比较并确定它相等。

要解决这个问题,请创建数组的副本并使用它更新状态:

const prevProducts = [...products];

【讨论】:

先生,这样做,我的 Home.js 中有产品,但我有点陷入尴尬的境地,我不知道如何定义它,但它有点像循环安慰。我现在只有无限数量的产品,而且还在不断增加 请检查我的以下答案【参考方案2】:

我不知道如何,但是当我使用相同的方法将我的功能组件 (ProductsContext.js) 更改为基于类的组件时,它以某种方式工作并且我能够在我的子组件中获取产品。这是代码

import React,  createContext  from 'react'
import  db  from '../Config/Config'

export const ProductsContext = createContext();

export class ProductsContextProvider extends React.Component 

    state = 
        products: []
    

    componentDidMount() 

        const prevProducts = this.state.products;
        db.collection('Products').onSnapshot(snapshot => 
            let changes = snapshot.docChanges();
            changes.forEach(change => 
                if (change.type === 'added') 
                    prevProducts.push(
                        ProductID: change.doc.id,
                        ProductName: change.doc.data().ProductName,
                        ProductDescription: change.doc.data().ProductDescription,
                        ProductPrice: change.doc.data().ProductPrice,
                        ProductImg: change.doc.data().ProductImg
                    )
                
                // console.log(prevProducts);
                this.setState(
                    products: prevProducts
                )
                // console.log(this.state.products);
            )
        )

    
    render() 
        return (
            <ProductsContext.Provider value= products: [...this.state.products] >
                this.props.children
            </ProductsContext.Provider>
        )
    

【讨论】:

以上是关于useContext 未在子组件中显示更新的状态(当从全局文件中的 useEffect 挂钩中的 firebase 检索数据时)的主要内容,如果未能解决你的问题,请参考以下文章

useContext 未在回调中更新其值

反应:useContext 值未在嵌套函数中更新

反应:无法使用 useContext 钩子在 app.js 中设置上下文状态

如何修改使用 useContext 传递的状态变量(不是 setState 修改,更像是可视化编辑)

Redux 状态未在开发工具中更新,但当前状态正在反映在道具中

来自父级的 TextField 默认值未在子级上呈现