如何将我的 API 调用结果保存到我的 redux 存储,并在我的组件首次加载时调用我的 API?

How to save the result of my API call to my redux store, and call my API when my component firsts loads?

所以我创建了一个 React redux 工具包应用程序,我正在尝试使用 redux 和操作。

我有一个简单的 React 组件,如下所示:

import React, { useState } from 'react';

import { useAppSelector, useAppDispatch } from '../../app/hooks';
import {
  setBoard,
  fetchBoardAsync,
  selectBoard
} from './boardSlice';
import styles from './Board.module.css';

export function Board() {
  const board = useAppSelector(selectBoard);
  const dispatch = useAppDispatch();

  console.log(JSON.stringify(board));

  return (
    <div>
      <div className={styles.row}>
        <h3>Board</h3>
       
        <button
          className={styles.asyncButton}
          onClick={() => dispatch(fetchBoardAsync(""))}
        >
          Fetch board Data from API
        </button>
      </div>
    </div>
  );
}

当我点击按钮时,它会获取一些 JSON - 但现在它只是硬编码的 json 变量。

// A mock function to mimic making an async request for data
export function fetchBoard() {
    return new Promise<{ data: any }>((resolve) =>
      setTimeout(() => resolve({ data: boardJson} ), 50)
    );
  }

其中 boardJson 很简单:

let boardJson = { .... }

我的 boardSlice 看起来像:

import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { RootState, AppThunk } from '../../app/store';
import { fetchBoard } from './boardAPI';

export interface BoardState {
  board: any;
  status: 'idle' | 'loading' | 'failed';
}

const initialState: BoardState = {
  board: {},
  status: 'idle',
};

export const fetchBoardAsync = createAsyncThunk(
  'board/fetchBoard',
  async (boardId: string) => {
    const response = await fetchBoard();
    console.log('fetch board returned data...' + JSON.stringify(response.data));
    return response.data;
  }
);

export const boardSlice = createSlice({
  name: 'board',
  initialState,
  // The `reducers` field lets us define reducers and generate associated actions
  reducers: {
      setBoard: (state, action: PayloadAction<any>) => {
          state.board = action.payload;
      }
  },

我有 2 个问题。

#1

当我单击按钮并获取板时,如何将结果保存到我的 redux 状态?

#2 另外,在我的 Board 组件中,如何在组件加载时 运行 fetchBoard 而不是必须单击按钮来触发它? (这曾经是一个组件生命周期事件,就像我认为的 componentDidMount)

When I click the button and it fetches the board, how do I save the result to my redux state?

您的 boardSlice reducer 几乎 达到了您的期望。在 reducers 字段中,您提供了一个 key/reducer 值的对象。 Redux 无法将键 setBoardfetchBoardAsync 创建的操作相关联。如果你要 dispatch({ type: 'setBoard', payload }) 那么你会看到你的减速器如预期的那样着火。请注意类型与 reducer key 的相同之处。

createAsyncThunk example from Redux documentation

Matching utilities in RTK

相反,您可以使用 RTK 构建器语法和匹配器来获得所需的结果:

export const boardSlice = createSlice({
  name: 'board',
  initialState,
  extraReducers(builder) {
    builder.addCase(fetchBoardAsync.fulfilled, (state, action) => {
      state.board = action.payload;
    })
  },
};

#2 Also, in my Board component, how can I run fetchBoard when the component loads instead of having to click a button to trigger it? (this used to be a component lifecycle event like componentDidMount I think)

在功能组件中,大多数 React 开发人员使用 React 钩子 useEffect 以类似于 componentDidMount/componentWillMountcomponentWillUnmount 的方式管理副作用。 The documentation 清楚地说明了开发人员可以利用此挂钩的所有方式。

例如:

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

import { useAppSelector, useAppDispatch } from '../../app/hooks';
import {
  setBoard,
  fetchBoardAsync,
  selectBoard
} from './boardSlice';
import styles from './Board.module.css';

export function Board() {
  const board = useAppSelector(selectBoard);
  const dispatch = useAppDispatch();
  useEffect(() => {
    dispatch(fetchBoardAsync(""))
  }, []); // an empty dependency array tells React to only run the effect after mount

  console.log(JSON.stringify(board)); // may not have loaded yet

  return (
    <div>
      {/* snip */}
    </div>
  );
}

一旦分派,thunk 就会收到第二个参数以实现额外的 Redux 功能。一个传统的 thunk,它是调度一个函数的结果,接收到带有这个签名的 redux API:

function fetchBoardAsync() {
  return (dispatch, getState) => {
    // now you can dispatch even more actions!
    // I don't believe this is necessary for your current use-case, but this is helpful for complicated side-effects in many apps
  }
}

Redux thunk documentation

使用createAsyncThunk时,签名是这样的:

function fetchBoardAsync(arg, api) {
  const { dispatch, extra, fulfillWithValue, getState, rejectWithValue, requestId, signal } = api;
}

createAsyncThunk signature

记住,在你使用 dispatch inside thunk 回调。