如何用TypeScript使用useSelector Redux钩子

820 阅读2分钟

Redux提供了useSelector钩子来从你的商店获取值。如果你使用的是Typescript,请确保你通过正确输入钩子来获得最大的收益。

一个有用户信息的基本商店

假设你有一个包含登录用户的一些信息的商店。我们将在这里做一个非常基本的存储设置,有一些动作创建者和一个还原器。

import { createStore } from 'redux';

type User = {
  name: string;
  age: number;
  admin: boolean;
};

const defaultUser: User = {
  name: 'Guest',
  age: 0,
  admin: false,
};

const setName = (payload: string) =>
  ({
    type: 'SET_NAME',
    payload,
  } as const);

const setAge = (payload: number) =>
  ({
    type: 'SET_AGE',
    payload,
  } as const);

const setAdmin = (payload: boolean) =>
  ({
    type: 'SET_ADMIN',
    payload,
  } as const);

type Actions = ReturnType<typeof setName | typeof setAge | typeof setAdmin>;

function reducer(state = defaultUser, action: Actions) {
  switch (action.type) {
    case 'SET_NAME':
      return { ...state, name: action.payload };
    case 'SET_AGE':
      return { ...state, age: action.payload };
    case 'SET_ADMIN':
      return { ...state, admin: action.payload };
    default:
      return state;
  }
}

const store = createStore(reducer);

type RootState = ReturnType<typeof store.getState>;

请注意,我在这里从store.getState 的返回类型推断出RootState 的类型,这有点不必要,因为我们的状态与User 相同,但在更复杂的情况下,这将是更有帮助。

使用useSelector钩子

我们现在想在Header 组件中显示我们用户的名字。如果没有类型,我们可以设想像这样使用useSelector 钩子。

import { useSelector } from 'react-redux';

export const Header = () => {
  const name = useSelector((state) => state.name);

  return <div>Welcome, {name}!</div>;
};

然而,如果我们的Typescript编译器大喊隐含any ,那么我们在这里就会出现编译错误。但此外,我们想从Typescript中获得最好的效果,所以在useSelector 中添加一些类型,以确保我们在状态中访问正确的路径,并确保我们的返回值是预期的类型,这对我们很重要。

为了给useSelector ,我们必须给它传递两个Generic :第一个Generic是我们整个状态对象的类型(记得我们创建了RootState !),第二个Generic是我们期望的返回值的类型(在这个例子中,我们期望name 是一个string )。

考虑到这一点,下面是我们如何为我们的useSelector 钩子打字。

import { useSelector } from 'react-redux';

export const Header = () => {
  const name = useSelector<RootState, string>((state) => state.name);

  return <div>Welcome, {name}!</div>;
};

现在我们的编译器很高兴,而且我们确信我们正在正确地访问我们状态上的name 属性。