react项目使用redux入门-2-工厂模式action分离优化

场景:切换语言

  1. 安装redux依赖包

    npm i redux --save
    
  2. 新建目录

    • 新建目录:src/reduxsrc/redux/language
    • 新建文件:src/redux/store.tssrc/redux/language/actionCreators.tssrc/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)
    
    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
      }
    }
    
  3. Header组件中使用store

    import { Component } from 'react'
    import { withRouter, RouteComponentProps } from 'react-router-dom'
    import { MenuInfo } from 'rc-menu/lib/interface'
    import { nanoid } from 'nanoid'
    import store from 'redux/store'
    import { LanguageState } from 'redux/language/reducer'
    import { LanguageActionProps, addLanguageActionCreator, changeLanguageActionCreator } from 'redux/language/actionCreators'
    
    const interface StateProps extends LangageState {}
    
    class HeaderComponent extends Component<RouteComponentProps, StateProps>{
      constructor(props:RouteComponentProps){
        super(props)
     		/* state初始化获取 store中的数据 */   
        const storeState = store.getState()
        this.state = {
          lng: storeState.lng,
          languageList: storeState.languageList
        }
      }
      
      componentDidMount(){
        /* subscribe */
        store.subscribe(() => {
          const storeState = store.getState()
          this.setState({
            lng: storeState.lng,
            languageList: storeState.languageList
          })
        })
      }
      
      render(){
        /* meun 的点击事件 */
        const oprateLanguage = ( e: MenuInfo ) => {
          let action
          if(e.key !== 'new'){
            action = changeLanguageActionCreator(e.key)
          }else{
           action = changeLanguageActionCreator({code: `lng${nanoid()}`, language: '新语种'})
          }
          /* dispatch */
          store.dispatch<LanguageActionProps>(action)
        }
        
        
        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 = withRouter(HeaderComponent)
    
posted @ 2022-01-11 13:58  shine_lovely  阅读(108)  评论(0编辑  收藏  举报