React Redux Hooks和TypeScript - 第二部分

202 阅读2分钟

上一篇文章中,我们实现了一个Redux商店,其中行动是同步的。在这篇文章中,我们将从相同的存储开始,使行动成为异步的。

React, Redux and TypeScript

状态

作为提醒,这里是我们的商店状态:

type Person = {
  id: number;
  name: string;
};
type AppState = {
  people: Person[];
};

所以,我们的应用状态包含一个人的数组。

这个应用程序将被刻意简化,这样我们就可以专注于Redux商店以及React组件如何以强类型的方式与之交互。

允许商店与异步操作一起工作

我们将使用Redux Thunk来允许Redux与异步操作一起工作。这是我们在创建商店时定义的中间件:

function configureStore(): Store<AppState> {
  const store = createStore(
    rootReducer,
    undefined,
    applyMiddleware(thunk)  );
  return store;
}

applyMiddleware 是Redux的一个函数,它允许我们向商店添加中间件,而 是Redux Thunk的中间件。thunk

行动和行动创建者

我们的动作创建者现在将是异步的。这里是添加一个人的动作创建器:

const addPerson = (personName: string) => async (
  dispatch: Dispatch<AddPersonAction>
) => {
  await wait(200);
  dispatch({
    type: "AddPerson",
    payload: personName,
  } as const);
};

在我们的例子中,我们正在用一个wait 函数来伪造一个异步函数。

addPerson 函数返回一个函数而不是动作对象,因为它是同步函数。内部函数接收了一个参数,dispatch ,这是另一个用于调度动作的函数。这是一个很多的函数!

注意,我们用Dispatch<AddPersonAction> 明确了dispatch 参数的类型。Dispatch 是Redux的一个标准类型,我们把动作的类型AddPersonAction 传递给它。这里是AddPersonAction 的定义:

type AddPersonAction = {
  readonly type: "AddPerson";
  readonly payload: string;
};

这里是移除一个人的动作创建者:

type RemovePersonAction = {
  readonly type: "RemovePerson";
  readonly payload: number;
};
const removePerson = (id: number) => async (
  dispatch: Dispatch<RemovePersonAction>
) => {
  await wait(200);
  dispatch({
    type: "RemovePerson",
    payload: id,
  } as const);
};

减速器

reduceraction 参数类型的创建方式与同步版本不同:

type Actions =
  | AddPersonAction
  | RemovePersonAction;

我们在同步版本中推断了动作类型,但在这里我们明确地创建了这些类型。

减速器的功能与同步版本完全相同:

function peopleReducer(
  state: Person[] = [],
  action: Actions
) {
  switch (action.type) {
    case "AddPerson":
      return state.concat({
        id: state.length + 1,
        name: action.payload,
      });
    case "RemovePerson":
      return state.filter(
        (person) => person.id !== action.payload
      );
    default:
      neverReached(action);
  }
  return state;
}

function neverReached(never: never) {}

酷!"。

连接组件

将React组件连接到商店,与同步版本完全相同。useSelector ,用于从商店获取数据:

const people: Person[] = useSelector(
  (state: AppState) => state.people
);

useDispatch 是用来调用存储动作的:

const dispatch = useDispatch();
...
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
  e.preventDefault();
  dispatch(addPerson(newPerson));
  ...
};
...
const dispatchNewPerson = (id: number) => () => {
  dispatch(removePerson(id));
};
...
<button onClick={dispatchNewPerson(person.id)}>Remove</button>

很好!

这个例子可以在CodeSandbox中找到:codesandbox.io/s/react-red…

包裹起来

Redux需要一个像Redux Thunk这样的库来处理异步操作。React组件与同步和异步动作的交互方式是一样的。主要的区别是在动作创建者方面。异步动作创建者返回一个最终派发动作对象的函数,而同步动作创建者立即返回动作对象。