如何在useReducer中调用api?

How to make api call in useReducer?

这是一个 class 组件,我想使用 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. https://website?property=${year} 进行 api 调用,然后填充 matchData
  3. 更新 firstCall

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

您似乎对reducer 模式不熟悉。 Reducers 是采用状态对象和应用于该状态的操作的纯函数,以及 returns 下一个状态对象。 reducer函数中有zeroside-effects

当状态 year 更新时,使用 useEffect 挂钩获取数据。您可能不希望为年份列表选项使用锚标记,因为单击它可能会尝试导航或重新加载 app/page。

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>
  );
};