useContext在子组件中不显示更新状态(从Firebase中的useEffect挂钩中从Firebase检索数据时)

时间:2020-11-05 07:42:12

标签: javascript reactjs use-effect react-context use-context

我正在使用上下文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

2 个答案:

答案 0 :(得分:0)

无论何时状态是一个对象(或数组,但从技术上讲也是一个对象),都必须避免对其进行突变。

在您的代码中,您正在对products数组进行突变,方法是在原始数组上调用push(...)而不是为其创建副本。

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

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

const prevProducts = [...products];

答案 1 :(得分:0)

我不知道如何,但是当我使用相同的方法将功能组件(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>
        )
    }
}
相关问题