首页 > 解决方案 > 如何在 useReducer 中进行 api 调用?

问题描述

这是我想重构为功能组件的类组件useReducer

export default class FootballMatchesData extends Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedYear: null,
      matchData: [],
      firstCall: false
    };
  }

  chooseYear = (year) => (e) => {
    this.setState({
      selectedYear: year
    })
    axios.get(`https://website?property=${year}`)
      .then(res => {
        this.setState({ matchData: res.data, firstCall: true })
      })
  }

  render() {
    ...
  }
}

我一直在定义减速器的“CHOOSE_YEAR”案例。我将如何定义这种情况,以便它:

  1. 更新selectedYear
  2. 对 进行 api 调用https://website?property=${year},然后填充matchData
  3. 更新firstCall

这是我当前的重构。https://codesandbox.io/s/gracious-pare-um66h?file=/src/FootballMatches.js

标签: reactjsreact-hooksuse-reducer

解决方案


您似乎对减速器模式不熟悉。Reducers 是一个纯函数,采用状态对象和动作应用于该状态,并返回下一个状态对象。reducer 函数的副作用为零。

在状态更新时使用useEffect钩子获取数据。year您可能不想同时为年份列表选项使用锚标签,因为单击它可能会尝试导航或重新加载应用程序/页面。

const initialState = {
  selectedYear: null,
  competitions: [],
  firstCall: false
};

const footballReducer = (state, action) => {
  switch (action.type) {
    case "CHOOSE_YEAR":
      return {
        selectedYear: action.year, // <-- save year payload
        firstCall: true
      };

    case "FETCH_BY_YEAR_SUCCESS":
      return {
        ...state, // <-- copy existing state
        competitions: action.competitions // <-- save competitions payload
      };
    default:
      throw new Error();
  }
};

const FootballMatches = () => {
  const [state, dispatchFootball] = useReducer(footballReducer, initialState);

  const yearChooseHandler = (year) => {
    dispatchFootball({ type: "CHOOSE_YEAR", year });
  };

  useEffect(() => {
    if (state.year) { // <-- ensure year value is truthy since null on initial render
      axios.get(`https://website?property=${state.year}`).then((res) => { // <-- access state.year for URL
        dispatchFootball({
          type: "FETCH_BY_YEAR_SUCCESS",
          competitions: res.data,
          firstCall: true
        });
      }
    });
  }, [state.year]); // <-- year dependency

  let years = [2011, 2012, 2013, 2014, 2015, 2016, 2017];
  return (
    <div>
      <div>Select Year</div>
      <ul>
        {years.map((year, idx) => {
          return (
            <li
              onClick={() => yearChooseHandler(year)} // <-- fix callback so it isn't invoked immediately and cause infinite render looping
              key={idx}
            >
              {year}
            </li>
          );
        })}
      </ul>

      ...
    </div>
  );
};

推荐阅读