REACT- firebase的上下文API
首先,我想说a)我是新手反应,b)我花了大约8个小时的时间试图在stackoverflow中挖掘修复程序,尝试了许多不同的方法。我被困。非常感谢您的时间。
此处的目的是等待Firebase的请求在渲染页面之前创建值“产品”。持续发生的是产品被加载为无效。
这是我的设置:
productContext.js
import React, {createContext, useState, useEffect} from 'react';
import { dummyProducts } from '../services/dummy';
import {collection, onSnapshot} from "firebase/firestore";
import {db} from "../firebase";
export const ProductsContext = createContext();
export function getProductData() {
const myArray =[];
return new Promise(function (resolve, reject) {
const querySnapshot = onSnapshot(collection(db, 'products'), (snapshot) => {
snapshot.forEach(doc => {
let productData = doc.data();
myArray.push(productData)
})
})
resolve(myArray);
});
}
const ProductsContextProvider = ({children}) => {
const [products, setProducts] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
let didCancel = false;
async function fetchMyAPI() {
let results = await getProductData();
console.log(results) // Outputs array with results
setProducts(results)
}
fetchMyAPI();
return () => { didCancel = true; }; // Remember if we start fetching something else
}, []);
return (
<ProductsContext.Provider value={{products}}>
{ children }
</ProductsContext.Provider>
);
}
export default ProductsContextProvider;
useproducts.js
// eslint-disable-next-line
import React, { useContext } from 'react';
import { ProductsContext } from '../contexts/ProductsContext';
export const useProducts = () => {
const ctx = useContext(ProductsContext)
return {
...ctx
}
}
productsgrid.js
import React from 'react';
import ProductItem from './ProductItem';
import styles from './ProductsGrid.module.scss';
import { useProducts } from '../../hooks/useProducts';
const ProductsGrid = () => {
const {products} = useProducts();
console.log(products.length) // Outputs zero
console.log(products) // Outputs array with 1 object (correct)
return (
<div className={styles.p__container}>
<div className="row">
<div className="col-sm-8">
<div className="py-3">
{products.length} Products
</div>
</div>
<div className="col-sm-4">
</div>
</div>
<div className={styles.p__grid}>
{
products.map(product => (
<ProductItem key={product.id} product={product}/>
))
}
</div>
<div className={styles.p__footer}>
</div>
</div>
);
}
export default ProductsGrid;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Routes from './routes';
import * as serviceWorker from './serviceWorker';
import { HelmetProvider } from 'react-helmet-async';
import ProductsContextProvider from './contexts/ProductsContext';
import CartContextProvider from './contexts/CartContext';
ReactDOM.render(
<HelmetProvider>
<ProductsContextProvider>
<CartContextProvider>
<Routes />
</CartContextProvider>
</ProductsContextProvider>
</HelmetProvider>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
serviceWorker.unregister();
First I want to say a) I am new to react, and b) I spent about 8hrs trying to dig around in stackoverflow for a fix, trying many different methods. I am stuck. Many thanks for your time.
The objective here is to wait for the request from firebase to create the value 'products', before rendering the page. What keeps happening is products gets loaded as null.
Here is my setup:
ProductContext.js
import React, {createContext, useState, useEffect} from 'react';
import { dummyProducts } from '../services/dummy';
import {collection, onSnapshot} from "firebase/firestore";
import {db} from "../firebase";
export const ProductsContext = createContext();
export function getProductData() {
const myArray =[];
return new Promise(function (resolve, reject) {
const querySnapshot = onSnapshot(collection(db, 'products'), (snapshot) => {
snapshot.forEach(doc => {
let productData = doc.data();
myArray.push(productData)
})
})
resolve(myArray);
});
}
const ProductsContextProvider = ({children}) => {
const [products, setProducts] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
let didCancel = false;
async function fetchMyAPI() {
let results = await getProductData();
console.log(results) // Outputs array with results
setProducts(results)
}
fetchMyAPI();
return () => { didCancel = true; }; // Remember if we start fetching something else
}, []);
return (
<ProductsContext.Provider value={{products}}>
{ children }
</ProductsContext.Provider>
);
}
export default ProductsContextProvider;
UseProducts.js
// eslint-disable-next-line
import React, { useContext } from 'react';
import { ProductsContext } from '../contexts/ProductsContext';
export const useProducts = () => {
const ctx = useContext(ProductsContext)
return {
...ctx
}
}
ProductsGrid.js
import React from 'react';
import ProductItem from './ProductItem';
import styles from './ProductsGrid.module.scss';
import { useProducts } from '../../hooks/useProducts';
const ProductsGrid = () => {
const {products} = useProducts();
console.log(products.length) // Outputs zero
console.log(products) // Outputs array with 1 object (correct)
return (
<div className={styles.p__container}>
<div className="row">
<div className="col-sm-8">
<div className="py-3">
{products.length} Products
</div>
</div>
<div className="col-sm-4">
</div>
</div>
<div className={styles.p__grid}>
{
products.map(product => (
<ProductItem key={product.id} product={product}/>
))
}
</div>
<div className={styles.p__footer}>
</div>
</div>
);
}
export default ProductsGrid;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Routes from './routes';
import * as serviceWorker from './serviceWorker';
import { HelmetProvider } from 'react-helmet-async';
import ProductsContextProvider from './contexts/ProductsContext';
import CartContextProvider from './contexts/CartContext';
ReactDOM.render(
<HelmetProvider>
<ProductsContextProvider>
<CartContextProvider>
<Routes />
</CartContextProvider>
</ProductsContextProvider>
</HelmetProvider>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
serviceWorker.unregister();
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
使它起作用。
我将
productionContext.js
和更改
为:
著名的更改为:
Got it working.
I changed
ProductsContext.js
And changed
ProductsGrid.js to:
Notable changes are: