【问题标题】:How to combine custom hook for data fetching and context?如何结合自定义钩子来获取数据和上下文?
【发布时间】:2019-09-01 14:29:32
【问题描述】:

我有一个自定义钩子来获取表单提交上的数据

export const getIssues = ({ user, repo }) => {
  const [issues, setIssues] = useState([]);

  const handleInputChange = (e) => {
    e.preventDefault();
    axios.get(`https://api.github.com/repos/${user}/${repo}/issues`)
      .then((response) => {
        setIssues(response.data);
      })
      .catch((err) => console.log(err));
  };

  return {
    issues,
    onSubmit: handleInputChange,
  };
};

在我的组件中我这样称呼它

const response = getIssues({ user: user.value, repo: repo.value })
  return (
    <form className={css['search-form']} {...response}>...</form>
)

问题是我想从另一个组件的钩子中获取我的issues 值。为此,我想使用上下文。但我不知道该怎么做。

我可以调用这个函数并将它传递给Provider,但我不能在没有参数的情况下调用它。所以我有点卡住了。

我们将不胜感激。

【问题讨论】:

  • 既然getIssues 是一个钩子,你应该称它为useIssues 一个linter 应该抱怨这个。 e.preventDefault 不属于问题挂钩,因为您提供了值 user.valuerepo.value 我假设您的表单以某种方式设置了这些,因此只需调用 useIssues 就足够了。

标签: reactjs


【解决方案1】:

您说得对,您需要React.Context 来处理这种情况。

  1. 您需要将组件包装到此上下文中。
import React from "react";

const IssuesStateContext = React.createContext();
const IssuesDispatchContext = React.createContext();

function issuesReducer(state, action) {
  switch (action.type) {
    case "setIssues": {
      return [...action.payload];
    }

    default: {
      throw new Error(`Unhandled action type: ${action.type}`);
    }
  }
}

function IssuesProvider({ children }) {
  const [state, dispatch] = React.useReducer(issuesReducer, []);
  return (
    <IssuesStateContext.Provider value={state}>
      <IssuesDispatchContext.Provider value={dispatch}>
        {children}
      </IssuesDispatchContext.Provider>
    </IssuesStateContext.Provider>
  );
}

function useIssuesState() {
  const context = React.useContext(IssuesStateContext);
  if (context === undefined) {
    throw new Error("useIssuesState must be used within a IssuesProvider");
  }
  return context;
}
function useIssuesDispatch() {
  const context = React.useContext(IssuesDispatchContext);
  if (context === undefined) {
    throw new Error("useIssuesDispatch must be used within a IssuesProvider");
  }
  return context;
}

export { IssuesProvider, useIssuesState, useIssuesDispatch };

通过在上下文中使用这种分离,您将能够在一个组件中设置来自 github 的问题,并将它们呈现在一个完全不同的组件中。

例子:

App.js

ReactDOM.render(
  <IssuesProvider>
    <Component1 />
    <Component2 />
  </IssuesProvider>
)

组件 1

import React from 'react'
import { useIssuesDispatch } from './issues-context'

function Component1() {
  const dispatch = useIssuesDispatch()
  // fetch issues
  // .then dispatch({ type: 'setIssues', payload: response })

  // render
}

组件 2

import React from 'react'
import { useIssuesState } from './issues-context'

function Component2() {
  const issues = useIssuesState()

  // if issues.length > 0 ? render : null
}

【讨论】:

    【解决方案2】:

    您可以编写一个提供{issues,useIssues} 的问题上下文提供程序,其中问题是问题,而useIssues 是一个接受{user,repo} 的函数。

    export const Issues = React.createContext();
    export default ({ children }) => {
      const [issues, setIssues] = useState([]);
      const useIssues = ({ user, repo }) => {
        useEffect(() => {
          axios
            .get(
              `https://api.github.com/repos/${user}/${repo}/issues`
            )
            .then(response => {
              setIssues(response.data);
            })
            .catch(err => console.log(err));
        }, [user, repo]);
        return issues;
      };
      return (
        <Issues.Provider value={{ issues, useIssues }}>
          {children}
        </Issues.Provider>
      );
    };
    

    拥有所有需要问题的组件的组件可以导入这个问题提供者:

    import IssuesProvider from './IssuesProvider';
    export default () => (
      <IssuesProvider>
        <ComponentThatNeedsIssues />
        <ComponentThatSetsAndGetsIssues />
      </IssuesProvider>
    );
    

    对于需要设置问题的组件,您可以从上下文中获取 useIssues:

    const { useIssues } = useContext(Issues);
    const issues = useIssues({user,repo});
    

    对于只需要问题的组件:

    const { issues } = useContext(Issues);
    

    要查看它们一起工作,有一个 codepen here

    【讨论】:

    • 如果我将 useIssues 函数放在我想要获取问题的组件中,每次我在字段中输入内容而不是提交时都会调用它
    • 如果我尝试调用它onSubmit 我收到错误Invalid hook call. Hooks can only be called inside of the body of a function component
    猜你喜欢
    • 2021-09-24
    • 1970-01-01
    • 2022-01-07
    • 1970-01-01
    • 2020-01-26
    • 2022-10-08
    • 2020-09-12
    • 1970-01-01
    • 2021-04-28
    相关资源
    最近更新 更多