場景:切換語言
使用react-redux的步驟
- 安裝
react-redux
依賴 - 在
src/index.tsx
中引入react-redux
中的Provider
,store
, 使用Provider,並加載store數據倉庫react-redux
使用react
的context
上下文,提供一個Provider API
,包裹 App組件,並加載store
,提供全局的store
- 在待使用的組件中使用
react-redux
中的connect
函數。connect
其實是個 高階hoc
,只是它沒有使用 withxxx的命名規范
具體使用
-
安裝
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 { Dispatch } from 'redux' import { connect } from 'react-redux' import store, { RootState } from 'redux/store' import { addLanguageActionCreator, changeLanguageActionCreator } from 'redux/language/actionCreators' /* connect 就是一個高階hoc,只不過它的命名沒有使用withxxxx來表示,class 類組件 使用 withxxx 高階hoc組件 使用了connect,就相當於store.subscribe, 即組件訂閱了store中的數據 */ /* mapStateToProps: 處理數據的流入。返回一個對象 使用connect函數,傳入mapStateToProps,完成store數據與組件的props綁定 */ // 高階hoc包裹的組件,可以獲取到一些額外的props或state屬性,connect函數傳入參數 mapStateToProps, 組件的props會被注入一些額外的props屬性 const mapStateToProps = (state: RootState) => { return { lng: state.lng, languageList: state.languageList } } /* mapDispatchToProps: 處理數據的流出。返回一個對象,對象中的每一個字段都是一個dispatch處理函數 將dispatch綁定到props中 */ const mapDispatchToProps = (dispatch: Dispatch) => { return { addLanguageDispatch: (language: { code: string, language: string }) => { dispatch(addLanguageActionCreator(language)) } changeLanguageDispatch: (lng: 'en'|'zh') => { dispatch(changeLanguageActionCreator(lng)) } } } class HeaderComponent extends Component<RouteComponentProps & ReturnType<typeof mapStateToProps> & ReturnType<typeof mapDispatchToProps>>{ render(){ const { history, lng, languageList, addLanguageDispatch, changeLanguageDispatch } = this.props /* meun 的點擊事件 */ const oprateLanguage = ( e: MenuInfo ) => { if(e.key !== 'new'){ changeLanguageDispatch(e.key) }else{ addLanguageDispatch({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> ) } } export const Header = connect(mapStateToProps, mapDispatchToProps)(withRouter(HeaderComponent))
-
store
數據封裝- 新建目錄:
src/redux
、src/redux/language
- 新建文件:
src/redux/store.ts
、src/redux/language/actionCreators.ts
,src/redux/language/reducers.ts
mkdir src/redux src/redux/language 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
- 工廠模式創建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 } }
- 新建目錄: