react项目使用redux入门-4-react-redux(在函数式类组件中使用, 使用hook)
场景:切换语言
使用react-redux的步骤
- 安装
react-redux
依赖 - 在
src/index.tsx
中引入react-redux
中的Provider
,store
, 使用Provider,并加载store数据仓库react-redux
使用react
的context
上下文,提供一个Provider API
,包裹 App组件,并加载store
,提供全局的store
- 在待使用的组件中使用
react-redux
中的useSelector
、useDispatch
hook函数。useSelector
获取store中的数据useDispatch
获取dispatch函数
具体使用
-
安装
react-redux
依赖包npm i react-redux --save npm i @types/react-redux --save-dev
-
src/index.tsx
import React from 'react' import ReactDOM from 'react-dom' import { Provider } from 'react-redux' // react-redux 利用上下文context,提供的数据组件Provider import 'antd/dist/antd.css' import './index.css' import App from './App' import 'i18n' import store from 'redux/store' ReactDOM.render( <React.StrictMode> {/* 使用Provider, 并加载 数据仓库 store, 就可以在全局范围内使用store */} <Provider store={store}> <App /> </Provider> </React.StrictMode>, document.getElementById('root') )
-
Header
组件中使用import { Component } from 'react' import { withRouter, RouteComponentProps } from 'react-router-dom' import { MenuInfo } from 'rc-menu/lib/interface' import { nanoid } from 'nanoid' // 使用react-redux // import { useDispatch, useSelctor } from 'react-redux' // const lng = useSelector<RootState>(state => state.lng) /* 使用useSelctor这个hook来获取store中的数据,其中一个目的就是解决组件与store数据耦合问题。 如果每次在组 件中使用useSelector都要传入RootState类型,就讲store与组件深度绑定,就将导致组件不能复用 => 所以,需要使用 TypeUseSelectorHook 这个interface,来讲RootStore 这个类型剥离开 */ import { useDispatch } from 'react-redux' import { useSelector } from 'redux/hooks' // 使用TypeUseSelectorHook这个interface 来重新定义 useSelector这个hook import { addLanguageActionCreator, changeLanguageActionCreator } from 'redux/language/actionCreators' export const Header = () => { const lng = useSelector(state => state.lng) const languageList = useSelector(state => state.languageList) const dispatch = useDispatch() /* meun 的点击事件 */ const oprateLanguage = ( e: MenuInfo ) => { if(e.key !== 'new'){ dispatch(changeLanguageActionCreator(e.key)) }else{ dispatch(changeLanguageActionCreator({code: `lng${nanoid()}`, language: '新语种'})) } } const menu = ( <Menu> <Menu.Item key='new' onClick={oprateLanguage}> 添加新语言 </Menu.Item> {languageList.map(language => ( <Menu.Item key={language.code} onClick={oprateLanguage}> {language.language} </Menu.Item> ))} </Menu> ) return ( <div> <Typography.Text className='mr40'>让旅游更幸福</Typography.Text> <Dropdown overlay={menu}> <Button> {languageList.find(language => language.code === lng)?.language} <GlobalOutlined /> </Button> </Dropdown> <Button.Group> <Button onClick={() => history.push('/signIn')}>登录</Button> <Button onClick={() => history.push('/register')}>注册</Button> </Button.Group> </div> ) }
-
store
数据封装- 新建目录:
src/redux
、src/redux/language
- 新建文件:
src/redux/store.ts
、src/redux/hooks.ts
、src/redux/language/actionCreators.ts
,src/redux/language/reducers.ts
mkdir src/redux src/redux/language touch src/redux/store.ts src/redux/hooks.ts touch src/redux/language/actionCreators.ts touch src/redux/language/reducer.ts
store.ts
import { createStore } from 'redux' import languageReducer form './language/reducer.ts' const store = createStore(languageReducer) // 使用ts的条件类型 ReturnType<T>,T:函数类型。 获取函数返回值的类型 export type RootState = ReturnType<typeof store.getState> export default store
hooks.ts
// 该文件将会导出 useSelector 与 react-redux中的 useSelector 重名, // 所以 使用 import { useSelector as useReduxSelector } from 'react-redux'进行重命名 import { useSelector as useReduxSelector, TypeUseSelectorHook } from 'react-redux' import { RootState } form 'redux/store' export const useSelector:TypeUseSelectorHook<RootState> = useReduxSelector
- 工厂模式创建action-
actionCreators.ts
/* 用常量定义action.type,减少代码敲错 */ export const ADD_LANGUAGE = 'language/add' export const CHANGE_LANGUAGE = 'language/change' /* action的类型申明 */ const AddActionProps = { type: typeof ADD_LANGUAGE, payload: { code: string, language: string } } const ChangeActionProps = { type: typeof CHANGE_LANGUAGE, payload: 'zh' | 'en' } export type LanguageActionProps = AddActionProps | ChangeActionProps /* 用工厂模式创建action */ export const addLanguageActionCreator = (language: {code: string, language: string}):ADD_LANGUAGE => { return { type: ADD_LANGUAGE, payload: language } } export const changeLanguageActionCreator = (lng: 'zh' | 'en'):CHANGE_LANGUAGE => { return { type: CHANGE_LANGUAGE, payload: lng } }
reducer.ts
import { ADD_LANGUAGE, CHANGE_LANGUAGE, LanguageActionProps } from './actions' export interface LanguageState { lng: 'zh' | 'en', languageList: {code: string, language: string}[] } const defaultStoreState: LanguageState = { lng: 'zh', languageList: [{ code: 'zh', language: '中文'}, { code: 'en', language: 'English'}] } export default (state = defaultStoreState, action:LanguageActionProps) => { switch (action.type) { case CHANGE_LANGUAGE: return { ...state, lng: action.payload } case ADD_LANGUAGE: return { ...state, languageList: [...state.languageList, action.payload] } default: return state } }
- 新建目录: