上下文API-多个提供程序+多个页面的React钩子?

时间:2019-06-23 18:27:41

标签: javascript reactjs

如何在不必将父组件与所有这些提供程序包装在一起的情况下简化React Context API提供程序?我有几个页面:主页,博客,联系人,图库和关于。我已经为联系页面创建了一个Context API Context和Provider。每个供应商都有自己独特的API,我正在使用带有React Hooks的Axios来获取。

我要问的是有一种方法可以保持我的代码干净整洁,而不是一遍又一遍地重复自己。

例如,我想要一个Context函数,可以一遍又一遍地使用它,并且只能获取一个唯一的Axios API URL的API数据。

我该怎么做?复制粘贴相同的东西..不干净。

PageContext.js: 

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

import axios from 'axios';

import PropTypes from 'prop-types';

import { PAGE_CONTACT } from 'constants/import';

export const PageContext = createContext();

export const PageProvider = props => {
    const [contactPage, setContactPage] = useState([]);

    useEffect(() => {
        axios.get(PAGE_CONTACT).then(result => setContactPage(result.data));
    }, []);

    return (
        <PageContext.Provider value={[contactPage, setContactPage]}>
            {props.children}
        </PageContext.Provider>
    );
};

PageProvider.propTypes = {
    children: PropTypes.oneOfType([
        PropTypes.arrayOf(PropTypes.node),
        PropTypes.node,
    ]).isRequired,
};

我使用上下文的页面联系人(组件):

import React, { useContext } from 'react';

import ReactHtmlParser from 'react-html-parser';

import { PageContext } from 'pages/context/PageContext';

const Contact = () => {
    const [field] = useContext(PageContext);

    return (
        <section className="contact">
            <div className="page">
                <div className="row">
                    <div className="col-xs-12">
                        <h3 className="section__title">{field.page_title}</h3>
                        {ReactHtmlParser(field.page_content)}
                        {field.page_featured_image && (
                            <img src={field.page_featured_image.path} />
                        )}
                    </div>
                </div>
            </div>
        </section>
    );
};

export default React.memo(Contact);

Index.js与提供程序包装在一起:

import React from 'react';
import ReactDOM from 'react-dom';

import { PageProvider } from 'pages/context/PageContext';

// Styles
import 'sass/root.scss';

// Root App
import App from './App';

import * as serviceWorker from './serviceWorker';

ReactDOM.render(
    <PageProvider>
        <App />
    </PageProvider>,
    document.getElementById('root')
);

serviceWorker.unregister();

1 个答案:

答案 0 :(得分:0)

这是一种有趣的方法,我个人不会将上下文用于您的解决方案。

我这样做的原因是,使用提供程序意味着您希望每个反应value道具都可以访问此children道具(这对于联系页面没有意义)。

我只能假定您的联系页面将具有仅该页面所需的内容?如果是这样,请做一些思考:

联系页面:

import React, { useState, useEffect } from "react";

import axios from "axios";
import ReactHtmlParser from "react-html-parser";

const Contact = () => {
  const [pageData, setPageData] = useState();

  useEffect(() => {
    axios.get(PAGE_CONTACT).then(result => {
      // Axios - check success!
      if (result.meta === 200) {
        setPageData(result.data);
      }
    });
    // You should be doing error handling here as well!
  }, []);

  return (
    <section className="contact">
      <div className="page">
        <div className="row">
          <div className="col-xs-12">
            {!!pageData ? (
              <>
                <h3 className="section__title">{pageData.page_title}</h3>

                {ReactHtmlParser(pageData.page_content)}

                {pageData.page_featured_image && (
                  <img src={pageData.page_featured_image.path} />
                )}
              </>
            ) : (
              <p>Some loading UI...</p>
            )}
          </div>
        </div>
      </div>
    </section>
  );
};

export default Contact;

我要说的是,这里的关键是要问您使用反应上下文的意图。将其添加到主要组件后,当值更改时将触发dom的重新渲染。

您可能拥有不依赖于联系页面的UX,例如关于页面。