【问题标题】:Using useEffect and useContext while fetching data在获取数据时使用 useEffect 和 useContext
【发布时间】:2019-09-11 05:00:30
【问题描述】:

我正在尝试学习如何使用 React 的 Context API 以及 Hooks,并尝试在我使用 fetch() 的项目上工作。

同时使用时,我得到了请求,但是我无法得到我设置的数据,除了loading

import React,{useState, createContext} from 'react';

export const ProductsContext = createContext();

export const ProductsProvider = props => {
    const [categories, setCategories] = useState({ categories: {} });
    const [products, setProducts] = useState({ products: {} });
    const [loading, setLoading] = useState(true);
    useEffect(() => {
        (async () => {
            const [categoriesResult, productsResult] = await Promise.all([fetch('http://localhost:3000/api/categories'), fetch('http://localhost:3000/api/products')]);
            setCategories(categoriesResult);
            setProducts(productsResult);
            setLoading(false);
          })();
        }, []);
    return (
    <ProductsContext.Provider value={ { products, categories, loading } }>
        {props.children}
    </ProductsContext.Provider>
    );
}

在这里,我正在创建一个我想通过 Provider 传递产品(和类别)的上下文。

import React, { useContext } from 'react';
import { ProductsContext } from './ProductsContext';


const Products = () => {
    const {products, categories, loading} = useContext(ProductsContext);
    return (
        <div className="products">
            { console.log(products, categories, loading) }
        </div>
    ); 
};

页面

import React from 'react';
import Header from './Header';
import Banner from './Banner';
import ProductsContainer from './Products/ProductsContainer';
import {ProductsProvider} from './Products/ProductsContext';
const Page = () => (

    <>
      <Header/>
      <Banner/>
      <ProductsProvider>
        <ProductsContainer/>
      </ProductsProvider>
    </>

);

export default Page;

这是我通过 console.log 得到的结果:

{products: {…}} Response {type: "basic", url: "http://localhost:3000/api/categories", redirected: false, status: 200, ok: true, …} true
Products.js:9 Response {type: "basic", url: "http://localhost:3000/api/products", redirected: false, status: 200, ok: true, …} Response {type: "basic", url: "http://localhost:3000/api/categories", redirected: false, status: 200, ok: true, …} true
Products.js:9 Response {type: "basic", url: "http://localhost:3000/api/products", redirected: false, status: 200, ok: true, …} Response {type: "basic", url: "http://localhost:3000/api/categories", redirected: false, status: 200, ok: true, …} false
Products.js:9 Response {type: "basic", url: "http://localhost:3000/api/products", redirected: false, status: 200, ok: true, …} Response {type: "basic", url: "http://localhost:3000/api/categories", redirected: false, status: 200, ok: true, …} false
Products.js:9 Response {type: "basic", url: "http://localhost:3000/api/products", redirected: false, status: 200, ok: true, …} Response {type: "basic", url: "http://localhost:3000/api/categories", redirected: false, status: 200, ok: true, …} false
Products.js:9 Response {type: "basic", url: "http://localhost:3000/api/products", redirected: false, status: 200, ok: true, …} Response {type: "basic", url: "http://localhost:3000/api/categories", redirected: false, status: 200, ok: true, …} false

如您所见,没有数据,但加载发生了变化。

我做错了什么?如何通过 Context API 传递产品?

【问题讨论】:

    标签: javascript reactjs next.js


    【解决方案1】:

    在随意阅读时,React.useContext() 看起来很有用。我看到的问题是 React 状态变量 categoriesproduct 被设置为来自 fetch() 的响应,并且根据 MDN's fetch() reference,fetch 返回一个从 Promise 解析为响应的值,即不完全是你想要的。

    但这很接近了!你应该做类似的事情

      setCategories(categoriesResult.json());
      setProducts(productsResult.json());
    

    或找出另一种方法将Response.Body 按摩成您可以操作的形式。 Check out the API reference for Response


    要解决承诺,您调用promise.then(...),其中promise 是从fetch() 返回的Promise 对象。

    为此,我建议将两个 fetch 分开,以使解决 Promise 变得简单,并可能使界面的其他部分更快地响应(即,如果一个 fetch 在另一个之前进入,您可以呈现这些结果,即使你没有另一个。即使你想等到两个部分都完成,你也可以让你的渲染取决于loading的状态。)

    export const ProductsProvider = props => {
      const [loading, setLoading] = useState(true);
    
      const [categories, setCategories] = useState({});
      useEffect(() => {
        fetch('http://localhost:3000/api/categories')
          .then((response) => {
             setCategories(response.json());
          }
        setLoading(/* false only if categories AND product are not {} */);
      }, []);
    
      // Repeat the above, except for products
    
      return (
        <ProductsContext.Provider value={ { products, categories, loading } }>
          {props.children}
        </ProductsContext.Provider>
      );
    }
    

    【讨论】:

    • 谢谢!这种方法有效,但是当 console.log 响应时,{ console.log(products, categories, loading) } 我得到了数据,但它在[[PromiseValue]] 中。我将如何从中访问数据?
    • 是的,您已经将两个 Promise 包装到另一个 Promise 中,因此您需要解决外部 Promise 以及内部 Promise,坦率地说,这使事情变得不必要地复杂化。请参阅更新的答案以获得简单的解决方案。
    猜你喜欢
    • 2020-06-12
    • 2021-06-14
    • 2019-09-29
    • 2021-08-16
    • 2021-01-26
    • 2022-01-22
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多