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
属性。