在获取数据时使用useEffect和useContext

时间:2019-09-08 21:24:17

标签: javascript reactjs next.js

我试图学习如何使用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>
    );
}

在这里,我正在创建一个上下文,希望通过提供程序传递产品(和类别)。

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传递产品?

1 个答案:

答案 0 :(得分:1)

在随意阅读时,React.useContext()看起来可维护。我看到的问题是,将React状态变量categoriesproduct设置为fetch()的响应,并且根据MDN's fetch() reference,fetch返回了一个从对响应的承诺,这不是您想要的。

但是,这很接近!您应该做类似

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

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


要兑现承诺,请致电promise.then(...),其中promise是从fetch()返回的 Promise 对象。

为此,我建议您将两个访存分开,以简化承诺的实现,并可能使界面的其他部分更快地响应(即,如果一个访存先于另一个访存,则即使您没有其他。即使您要等到两个部分都完成后,也可以使渲染取决于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>
  );
}