使用钩子获取数据

时间:2020-05-13 15:44:34

标签: javascript reactjs react-hooks

我很难全神贯注地以最佳方式从API一次(以及在首次请求时)获取数据,然后存储结果以供重用和/或其他组件功能。下面是一个useContextuseReducer的工作示例,但是对于这样一个“简单”的任务来说,它非常复杂。

有没有更好的方法?对于大量的API调用,实现此目标的最佳方法是什么。任何建议都将不胜感激。

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

const initialState = {
  items: [],
  itemsLoading: false
};

const actions = {
  FETCHING_ITEMS: "FETCHING_ITEMS",
  FETCHED_ITEMS: "FETCHED_ITEMS"
};

const reducer = (state, action) => {
  switch (action.type) {
    case actions.FETCHING_ITEMS:
      return { ...state, itemsLoading: true, items: {} };

    case actions.FETCHED_ITEMS:
      return { ...state, items: action.value };
    default:
      return state;
  }
};

const Context = React.createContext();

const Provider = ({ children }) => {
  const [state, dispatch] = React.useReducer(reducer, initialState);

  const value = {
    items: state.items,
    itemsLoading: state.itemsLoading,
    fetchItems: () => {
      if (!state.itemsLoading) {
        dispatch({ type: actions.FETCHING_ITEMS });
        axios
          .get("https://jsonplaceholder.typicode.com/todos")
          .then(function(response) {
            dispatch({ type: actions.FETCHED_ITEMS, value: response.data });
          });
      }
    }
  };

  return <Context.Provider value={value}>{children}</Context.Provider>;
};

const Filters = () => {
  const { items, fetchItems } = React.useContext(Context);

  React.useEffect(() => {
    fetchItems();
  }, [fetchItems]);

  const listItems = items.length
    ? items.map(item => {
        return <li key={item.id}>{item.title}</li>;
      })
    : "";

  return (
    <div>
      <ul>{listItems}</ul>
    </div>
  );
};

const App = () => {
  return (
    <Provider>
      <Filters />
    </Provider>
  );
};

const rootElement = document.getElementById("root");

ReactDOM.render(
    <App />,
  rootElement
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

无法使代码段在SO上运行,这是一个有效的沙箱:https://codesandbox.io/s/falling-frog-4pdm1

谢谢!

1 个答案:

答案 0 :(得分:1)

我想您可以使用custom hooks-

对此进行一些抽象
int main()  
{  
    char arr[] = { "Q, R, Y, M, N, L, O" };
    int n = sizeof(arr) / sizeof(arr[0]);

    insertionSort(arr, n);  
    printArray(arr, n);  

    return 0;  
}

您很兴奋,所以您可以立即开始使用它-

const identity = x => x

const useAsync = (runAsync = identity, deps = []) => {
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)
  const [result, setResult] = useState(null)

  useEffect(_ => {
    Promise.resolve(runAsync(...deps))
      .then(setResult, setError)
      .finally(_ => setLoading(false))
  }, deps)

  return { loading, error, result }
}

但是到此为止。在需要时编写更多有用的钩子-

const MyComponent = () => {
  const { loading, error, result:items } =
    useAsync(_ => {
      axios.get("path/to/json")
        .then(res => res.json())
    }, ...)

  // ...
}

方便地useEffect仅在依赖项更改时才重新运行效果。但是,如果您希望通过更精细的控制来处理昂贵的查询,请查看useCallbackuseMemo