react-redux 可以全局传递 store, 让所有组件都可以直接使用 store 的 state 和 dispatch
官方文档
安装
yarn add react-redux
yarn add -D @types/react-redux
Provider
在入口文件index.tsx中引入Provider和store, 将App组件包裹,则App组件内的所有组件都可以访问store
// ...
import {Provider} from 'react-redux'
import store from './redux/store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
connect
connect函数可以将 state 和 dispatch 映射到组件的 props 中,组件通过 props 访问 state 和调用 dispatch 方法
connect在类组件中更常用
mapStateToProps
connect接受2个参数,第一个参数是mapStateToProps, 顾名思义,就是把state映射到props上
const mapStateToProps = (state) => {
return {
language: state.language,
languageList: state.languageList
}
}
组件中就可以直接通过props访问到state了
const language = props.language
const languageList = props.languageList
mapDispatchToProps
第二个参数是mapDispatchToProps, 即将 dispatch 映射到props
mapDispatchToProps有2中形式,一种是简单的javascript对象,对象里面是action creator函数,
// import action creator
import {
addLanguageActionCreator,
changeLanguageActionCreator,
} from '../../redux/language/languageActions'
const mapDispatchToProps = {
addLanguageActionCreator,
changeLanguageActionCreator
}
connect将action creator封装成了自带dispatch的形式,通过props调用action creator就触发了dispatch
const menuClickHandler = (e) => {
if (e.key === 'new') {
props.addLanguageActionCreator('新语言', 'new_lang')
} else {
props.changeLanguageActionCreator(e.key)
}
}
mapDispatchToProps的第二种形式是函数,可用于更复杂的情况, 一般对象形式就够用了
const mapDispatchToProps = (dispatch: Dispatch) => {
return {
changeLanguage: (code: "zh" | "en") => {
const action = changeLanguageActionCreator(code);
dispatch(action);
},
addLanguage: (name: string, code: string) => {
const action = addLanguageActionCreator(name, code);
dispatch(action);
},
};
};
Typescript类型
最后,千万别忘了,以上的使用都建立在把组件传递给 connect 的基础上
以下是用TS添加了类型的版本
注意:
- ReturnType用于获得函数的返回值的类型
- typescript中 & 运算符得到的是交叉类型,即多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。 ```tsx import { createStore } from ‘redux’ import languageReducer from ‘./language/languageReducer’
const store = createStore(languageReducer)
// 在 store 中导出 state 的类型 RootState
export type RootState = ReturnType
```tsx
import { connect } from 'react-redux'
import { RootState } from '../../redux/store'
import { Dispatch } from "redux";
const mapStateToProps = (state: RootState) => {
return {
language: state.language,
languageList: state.languageList
}
}
const mapDispatchToProps = (dispatch: Dispatch) => {
return {
changeLanguage: (code: "zh" | "en") => {
const action = changeLanguageActionCreator(code);
dispatch(action);
},
addLanguage: (name: string, code: string) => {
const action = addLanguageActionCreator(name, code);
dispatch(action);
},
};
};
type PropsType = ReturnType<typeof mapStateToProps> &
ReturnType<typeof mapDispatchToProps>;
const HeaderComponent:React.FC<PropsType> = (props) => {
const language = props.language
const languageList = props.languageList
const menuClickHandler = (e) => {
if (e.key === 'new') {
props.addLanguage('新语言', 'new_lang')
} else {
props.changeLanguage(e.key)
}
}
return (
// ...
)
}
export const Header = connect(mapStateToProps, mapDispatchToProps)(HeaderComponent)
使用 react-redux 后,组件不需要对 store 进行 subscribe, 当 state 变化时,页面会自动重新渲染
hooks
react-redux 还提供了更加简洁且适合函数式组件使用的hooks来访问 store 的 state 和 dispatch
- useSelector: 用于在组件内获取 store 的state
- useDispatch: 用于在组件内获取dispatch方法 ```tsx import { addLanguageActionCreator, changeLanguageActionCreator, } from ‘../../redux/language/languageActions’ import { useSelector, useDispatch } from ‘react-redux’ import { RootState } from ‘../../redux/store’
export const Header:React.FC = () => { const language = useSelector((state:RootState) => state.language) const languageList = useSelector((state:RootState) => state.languageList) const dispatch = useDispatch()
const menuClickHandler = (e) => { if (e.key === ‘new’) { dispatch(addLanguageActionCreator(‘新语言’, ‘new_lang’)) } else { dispatch(changeLanguageActionCreator(e.key)) } }
return ( // … ) }
<a name="PkE33"></a>
### define typed hooks
[参考文档](https://react-redux.js.org/using-react-redux/usage-with-typescript)<br />因为使用了 typescript, 在组件内使用 useSelector 是需要指定 state 的类型为 RootState<br />为了不用每次使用 useSelector 或 useDispatch 时都要在组件内指定类型,我们可以预先为 useSelector 和useDispatch 指定类型
先在store.ts中将 state 和 dispatch 的类型导出
```tsx
import { createStore } from 'redux'
import languageReducer from './language/languageReducer'
const store = createStore(languageReducer)
export default store
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
新建redux/hooks.ts文件, 导出新的有类型的 useSelector 和 useDispatch
import { TypedUseSelectorHook,
useDispatch as useReduxDispatch,
useSelector as useReduxSelector} from 'react-redux'
import type { RootState, AppDispatch } from './store'
export const useDispatch = () => useReduxDispatch<AppDispatch>()
export const useSelector: TypedUseSelectorHook<RootState> = useReduxSelector
在组件中都改用 hooks.ts 中的 useSelector 和 useDispatch 就不用再指定类型了
import { useSelector, useDispatch } from '../../redux/hooks'
export const Header:React.FC = () => {
const language = useSelector((state) => state.language)
const languageList = useSelector((state) => state.languageList)
const dispatch = useDispatch()
// ...