【问题标题】:Storing Axios response in AppContext在 AppContext 中存储 Axios 响应
【发布时间】:2020-09-15 19:14:57
【问题描述】:

我正在尝试构建我网站的一个部分,该部分将动态地从 REST API 中提取联系信息。此时我正在使用来自 https://jsonplaceholder.typicode.com 的示例 API。

我正在尝试使用axios,特别是useAxiosmakeUseAxios 挂钩来获取API,并将其存储在我可以在整个站点中使用的应用程序上下文中,最好使用@987654326 @ 钩。此外,我需要能够根据用户交互更新 API 调用,允许他们选择位置、更新 API 并将其存储在应用程序的上下文中,以便动态更新。

基本上,我已经获得了一个基于this tutorial 的基本useContext 场景,但我正在努力解决如何以可以在useContext 中引用它的方式存储JSON 响应。这是迄今为止我做过的最接近的事情:

AppContext.tsx

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

import axios from 'axios';
import { makeUseAxios } from 'axios-hooks';
import { useCookie } from 'hooks/use-cookie';

export const AppContext = createContext();

export const DealerContextProvider = ({children}: any) => {
  const useAxios = makeUseAxios({
    axios: axios.create({ baseURL: 'https://jsonplaceholder.typicode.com/users/' }),
  });

  const LOCAL_STORAGE_KEY_DEALER = '_selectedDealerInformation';

  const [cookie] = useCookie('one-day-location', '1');
  const [dealerInfo] = useAxios(`${cookie}`);

  return (
    <AppContext.Provider value={[dealerInfo]}>
      {children}
    </AppContext.Provider>
  );
};

还有我的标题组件,我正在尝试访问它:

import React, { ReactNode, useEffect, useState, useContext } from 'react';

import { AppContext } from 'components/app-context/AppContext';

import Logo from 'assets/svg/logo.svg';
import css from 'classnames';
import { Button } from 'components/button/Button';
import { Link } from 'components/link/Link';

import { NotificationBar } from '../notification-bar/NotificationBar';
import s from './Header.scss';
import { MenuIcon } from 'components/menu-icon/MenuIcon';
import { MainNav } from './navigation/MainNav';

interface HeaderProps {
  navigationContent: ReactNode;
}

export const Header = ({ navigationContent }: HeaderProps) => {
  const [scrolled, setScrolled] = useState(false);
  const [open, setOpen] = useState(false);

  const blogInfo = useContext(AppContext);
  const buttonLabel = blogInfo ? `${blogInfo.name}` : 'Find a Dealer';
  const buttonLink = blogInfo ? `tel:${blogInfo.name}` : '/find-a-dealer';

  useEffect(() => {
    const handleScroll = () => {
      const isScrolled = window.scrollY > 10;
      if (isScrolled !== scrolled) {
        setScrolled(!scrolled);
      }
    };

    document.addEventListener('scroll', handleScroll, { passive: true });

    return () => {
      document.removeEventListener('scroll', handleScroll);
    };
  }, [scrolled]);

  return (
    <>
      <NotificationBar notificationContent={navigationContent} />
      <header
        className={scrolled ? css(s.header, s.header__scrolled) : s.header}
        data-open={open ? 'true' : ''}
      >
        <nav className={s.header__navigation}>
          <ul className={s.header__container}>
            <li className={s.header__logo}>
              <Link to="/" className={s.header__link}>
                <Logo />
              </Link>
            </li>

            <li className={s.header__primary}>
              <MainNav navigationItems={navigationContent} />
            </li>

            <li className={s.header__utility}>
              <Button href={buttonLink}>{buttonLabel}</Button>
            </li>

            <li className={s.header__burger}>
              <MenuIcon onClick={() => setOpen(!open)} />
            </li>
          </ul>
        </nav>
      </header>
    </>
  );
};

我需要header__utility 中的按钮动态显示所选经销商的姓名和电话号码。我可以根据需要澄清任何事情,我对 React 很陌生,并且仍在学习如何表达我需要的所有内容。

谢谢!

【问题讨论】:

    标签: javascript reactjs axios react-hooks use-context


    【解决方案1】:

    好的,我在过去 24 小时内进行了大量挖掘工作,终于找到了解决方案。

    我有我的上下文,为了清楚起见,现在命名为 ApiContext

    ApiContext.tsx

    import React, { createContext } from 'react';
    
    import axios from 'axios';
    import { makeUseAxios } from 'axios-hooks';
    import { useCookie } from 'hooks/use-cookie';
    
    const contextObject = {} as any;
    
    export const context = createContext(contextObject);
    
    const useAxios = makeUseAxios({
      axios: axios.create({ baseURL: process.env.GATSBY_API_ENDPOINT }),
    });
    
    export const ApiContext = ({ children }: any) => {
      const [cookie] = useCookie('one-day-location', '1');
    
      const [{ data }] = useAxios(`${cookie}`);
    
      const { Provider } = context;
      return <Provider value={data}>{children}</Provider>;
    };
    

    然后,为了跨组件使用它,我将 AppLayout 包装在 &lt;ApiContext&gt; 中:

    AppLayout.tsx

    import React, { ReactNode } from 'react';
    
    import { ApiContext } from 'contexts/ApiContext';
    import { graphql, StaticQuery } from 'gatsby';
    
    import { Devtools } from '../devtools/Devtools';
    import { Footer } from '../footer/Footer';
    import { Header } from '../header/Header';
    import s from './AppLayout.scss';
    
    interface AppLayoutProps {
      children: ReactNode;
      location: string;
    }
    
    const isDev = process.env.NODE_ENV === 'development';
    
    // tslint:disable no-default-export
    export default ({ children }: AppLayoutProps) => {
      return (
        <StaticQuery
          query={`${NavQuery}`}
          render={(data) => (
            <>
              <ApiContext>
                <Header navigationContent={data.prismic.allNavigations.edges[0].node} />
    
                <div className={s.layout}>
                  {children}
    
                  <Footer navigationItems={data.prismic.allNavigations.edges[0].node} />
    
                  {isDev && <Devtools />}
                </div>
              </ApiContext>
            </>
          )}
        />
      );
    };
    
    const NavQuery = graphql`
      query NavQuery {
        prismic {
          allNavigations {
            edges {
              node {
                ...NotificationBar
                ...NavigationItems
                ...FooterNavigationItems
              }
            }
          }
        }
      }
    `;
    

    在我的Header 组件中,我可以使用useContext 挂钩访问数据:

    Header.tsx

    import React, { ReactNode, useContext, useEffect, useState } from 'react';
    
    import Logo from 'assets/svg/logo.svg';
    import css from 'classnames';
    import { Button } from 'components/button/Button';
    import { Link } from 'components/link/Link';
    import { MenuIcon } from 'components/menu-icon/MenuIcon';
    import { context } from 'contexts/ApiContext';
    
    import { NotificationBar } from '../notification-bar/NotificationBar';
    import s from './Header.scss';
    import { MainNav } from './navigation/MainNav';
    
    interface HeaderProps {
      navigationContent: ReactNode;
    }
    
    export const Header = ({ navigationContent }: HeaderProps) => {
      const [scrolled, setScrolled] = useState(false);
      const [open, setOpen] = useState(false);
    
      const data = useContext(context);
    
      console.log(data);
    
      const buttonLabel =  data ? data.name : 'Find a Dealer';
      const buttonLink = data ? `tel:${data.phone}` : '/find-a-dealer';
    
      useEffect(() => {
        const handleScroll = () => {
          const isScrolled = window.scrollY > 10;
          if (isScrolled !== scrolled) {
            setScrolled(!scrolled);
          }
        };
    
        document.addEventListener('scroll', handleScroll, { passive: true });
    
        return () => {
          document.removeEventListener('scroll', handleScroll);
        };
      }, [scrolled]);
    
      return (
        <>
          <NotificationBar notificationContent={navigationContent} />
          <header
            className={scrolled ? css(s.header, s.header__scrolled) : s.header}
            data-open={open ? 'true' : ''}
          >
            <nav className={s.header__navigation}>
              <ul className={s.header__container}>
                <li className={s.header__logo}>
                  <Link to="/" className={s.header__link}>
                    <Logo />
                  </Link>
                </li>
    
                <li className={s.header__primary}>
                  <MainNav navigationItems={navigationContent} />
                </li>
    
                <li className={s.header__utility}>
                  <Button href={buttonLink}>{buttonLabel}</Button>
                </li>
    
                <li className={s.header__burger}>
                  <MenuIcon onClick={() => setOpen(!open)} />
                </li>
              </ul>
            </nav>
          </header>
        </>
      );
    };
    

    我仍在进行其他优化,特别是在加载页面时消除闪烁,并在单击按钮时更新 API,使用 useCookie,这是我构建的自定义挂钩。希望这能让其他搜索此信息的人更加清楚,我花了好几个小时来确定解决方案。干杯。

    【讨论】:

      猜你喜欢
      • 2019-04-03
      • 2021-11-11
      • 2021-06-23
      • 2019-03-11
      • 2021-09-13
      • 1970-01-01
      • 2022-01-18
      • 2021-03-05
      • 1970-01-01
      相关资源
      最近更新 更多