zoukankan      html  css  js  c++  java
  • react redux 二次开发流程

    在一个大项目中如何引入redux及其相关技术栈(react-redux redux-thunk redux-immutable ),已经成为react前端工程师不可或缺的技能,下面通过实现一个简单的todolist效果,来介绍相关流程

    1.引入redux进行应用数据管理,安装相关依赖

    yarn add redux  react-redux redux-thunk redux-devtools-extension
    一般目录结构

    2.创建好store.js、reducer.js、action.js、action-types.js

    1)store.js
    1 /*
    2 redux最核心的管理对象store
    3  */
    4 import {createStore} from 'redux'
    5 import reducer from './reducer'
    6 
    7 const  store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())
    8 // 向外默认暴露store
    9 export default  store

     2) reducer.js

     1 import {CHANGEINPUT,ADDITEMS } from './action-types'
     2 
     3 const defalutState = {
     4     inputValue : 'wuxiaohui',
     5     list :[]
     6 }
     7 
     8 export default (state = defalutState,action) =>{
     9     if(action.type === CHANGEINPUT){
    10         let newState = JSON.parse(JSON.stringify(state))//深拷贝
    11         newState.inputValue = action.value
    12         return newState
    13     }
    14     if(action.type === ADDITEMS){
    15         let newState = JSON.parse(JSON.stringify(state))
    16         newState.list.push(newState.inputValue)
    17         newState.inputValue = ''
    18         return newState
    19     }
    20 
    21     return state
    22 }

    3)action.js

    import {CHANGEINPUT,ADDITEMS } from './action-types'
    
    export const inputChange = (e)=>({
        type:CHANGEINPUT,
        value:e.target.value
    })
    
    export const clickButton = ()=>({
        type:ADDITEMS
    })

    4)action-types.js

    /*
    包含n个action type常量名称的模块
     */
    export const CHANGEINPUT = 'change_input'
    export const ADDITEMS = 'add_item'

    3.创建todolistui组件

    编写TodolistUI.js,由于没有双向绑定,通过onChange的inputChange事件拿到输入值并通过inputValue传回给输入框,clickButton则是向list中追加输入框中输入的数据,输入后清空。该逻辑在 reducer.js中体现,UI组件只负责展示。
     
    //把TodoList改为UI组件-提高性能
    
    import React from "react";
    
     const TodoListUI =(props)=>{
    // 接收connect连接器映射传递的属性和函数
        let {inputValue ,inputChange,clickButton,list} = props; 
        return (
    
            <div>
                <div>
                    <input value={inputValue} onChange={inputChange} />
                    <button onClick={clickButton}>提交</button>
                </div>
                <ul>
                    {
                        list.map((item,index)=>{
                            return (<li key={index}>{item}</li>)
                        })
                    }
                </ul>
            </div>
        );
    }
    export  default TodoListUI

    4.引入react-redux进行应用数据管理

    1)总入口中index.js中引入react-redux和容器组件APP
    react-redux的核心:Provider(用于入口) 和 connect(用于数据和函数映射)
    使用provider
    /*
    入口js
     */
    import React from 'react';
    import ReactDOM from 'react-dom';
    
    import App from './containers/App';
    import { Provider} from 'react-redux'
    import store from './redux/store'
    
    //<Provider>是一个提供器,只要使用了这个组件,组件里边的其它所有组件都可以使用store了
    //声明一个App容器组件,然后这个组件用Provider进行包裹。
    const  AppList = (
        <Provider store={store}>
            <App />
        </Provider>
    )
    ReactDOM.render(AppList, document.getElementById('root'));
    2)connect连接器(连接UI组件和redux中的action.js方法)成为容器组件
    connect-连接器用来将redux管理的state数据映射成UI组件的一般属性(如输入框的值)
    connect-连接器用来将redux管理的包含diaptch代码的函数映射成UI组件的函数属性的函数
    1.在redux目录中的action.js定义UI组件要调用的方法,然后编写好reducer的业务逻辑
    2.在containers容器APP组件中 引入UI组件TodolistUI和action进行连接
    import React from 'react'
    import {connect} from 'react-redux'
    
    import TodoListUI from '../components/TodoListUI'
    import {inputChange,clickButton} from '../redux/actions'
    
    /*
    connect-连接器用来将redux管理的state数据映射成UI组件的一般属性(如输入框的值)
     指定向TodoList传入哪些一般属性(属性值的来源就是store中的state)
     */
    const stateToProps = (state)=>{
        return {
            inputValue : state.inputValue,
            list:state.list
        }
    }
    
    /*
    connect-连接器用来将redux管理的包含diaptch代码的函数映射成UI组件的函数属性的函数
    (如输入的onChange事件)
    可以写多个函数,用逗号隔开
     */
    // 写法1
    // const dispatchToProps = (dispatch) =>{
    //     return {
    //         inputChange(e){
    //             //派发action到store中:定义action 然后派发
    //             //派发后就在reducer里边,编写对应的业务逻辑了
    //             let action = {
    //                 type:'change_input',
    //                 value:e.target.value
    //             }
    //             dispatch(action)
    //         },
    //         clickButton(){
    //
    //             let action = {type:'add_item'}
    //             dispatch(action)
    //         }
    //     }
    // }
    //export default connect(stateToProps,dispatchToProps )(TodoListUI);
    
    // 写法2
    export default connect(stateToProps,{inputChange,clickButton} )(TodoListUI);
    5.引入 immutablejs
    首先,我们有必要来划分一下边界,哪些数据需要使用不可变数据,哪些数据要使用原生js数据结构,哪些地方需要做互相转换
    • 在redux中,全局state必须是immutable的,这点毋庸置疑是我们使用immutable来优化redux的核心
    • 组件props是通过redux的connect从state中获得的,并且引入immutableJS的另一个目的是减少组件shouldComponentUpdate中不必要渲染,shouldComponentUpdate中比对的是props,如果props是原生JS就失去了优化的意义
    • 组件内部state如果需要提交到store的,必须是immutable,否则不强制
    • view提交到action中的数据必须是immutable
    • Action提交到reducer中的数据必须是immutable
    • reducer中最终处理state必须是以immutable的形式处理并返回
    • 与服务端ajax交互中返回的callback统一封装,第一时间转换成immutable数据

    1)安装相关依赖

    yarn add immutable  redux-immutable 

    2)在reducer中 immutable的fromJs,把defalutState 转为immutable数据

     1 // 引入fromJS 将state数据转变为 immutable对象
     2 const defalutState = fromJS({
     3     inputValue : 'wuxiaohui',
     4     list :[]
     5 });
     6 
     7 //immutablejs的相关接口——使用get 和set 方法来改变state
     8 export default (state = defalutState,action) =>{
     9     if(action.type === CHANGEINPUT){
    10         // let newState = JSON.parse(JSON.stringify(state)) //深拷贝
    11         // newState.inputValue = action.value
    12         // return newState
    13         return  state.set('inputValue',action.value)
    14     }
    15     if(action.type === ADDITEMS){
    16         // let newState = JSON.parse(JSON.stringify(state))
    17         // newState.list.push(newState.inputValue)
    18         // newState.inputValue = ''
    19         // return newState
    20         
    21         return state.merge({
    22             'list': state.get('list').push(state.get('inputValue')),
    23             'inputValue': ''
    24         });
    25 
    26     }
    27 
    28     return state
    29 }

    3)在容器组件中App.js中映射时使用get获取相关属性值

     1 /*
     2 connect-连接器用来将redux管理的state数据映射成UI组件的一般属性(如输入框的值)
     3  指定向TodoList传入哪些一般属性(属性值的来源就是store中的state)
     4  */
     5 const stateToProps = (state)=>{
     6     return {
     7         // inputValue : state.inputValue,
     8         // list:state.list
     9         //因为引入了immutable,state 已变为不可变对象只能调用get或set方法
    10         inputValue : state.get('inputValue'),
    11         list:state.get('list')
    12     }
    13 }
    更多用法:
     

    4)redux-immutable在reducer的处理

    combineReducers(reducers)
    随着应用变得越来越复杂,可以考虑将 reducer 函数 拆分成多个单独的函数,拆分后的每个函数负责独立管理 state 的一部分

    类似这样

     1 import { combineReducers } from 'redux';
     2 import { reducer as headerReducer } from '../common/header/store';
     3 import { reducer as homeReducer } from '../pages/home/store';
     4 import { reducer as detailReducer } from '../pages/detail/store';
     5 import { reducer as loginReducer } from '../pages/login/store';
     6 
     7 const reducer = combineReducers({
     8    header: headerReducer,
     9    home: homeReducer,
    10    detail: detailReducer,
    11    login: loginReducer
    12 });
    13 
    14 export default reducer;

    假如我们的reducer在header中,组件中获取数据时,用get方法

    const mapStateToProps = (state) => {
        //inputValue是immutable对象,不能用state.header.inputValue的形式获取,要用get()
          return  {
              inputValue :state.header.get('inputValue'),
              list:state.header.get('list')    
          }    
    }

    在使用了redux-immutable

    1 //combineReducers不再用rudux里的,而是redux-immutable里的,这样combineReducers里的对象就是一个immutable对象
    2 //import {combineReducers} from 'redux'
    3 import {combineReducers} from 'redux-immutable'
    4 import {reducer as headerReducer} from '../common/header/store'
    5 const reducer=combineReducers({
    6     header:headerReducer
    7 });
    8 export default reducer;

    获取数据的时候用get(),或者getIn()--获取结构化数据

    1 const mapStateToProps = (state) => {    
    2       return  {
    3           //inputValue :state.header.get('inputValue'),
    4          // list:state.header.get('list') 
    5              inputValue :state.getIn(['header','inputValue']),
    6              list:state.getIn(['header','list'])
    7       }    
    8 }
     
    流程中例子详见GitHub
  • 相关阅读:
    [cf 599A]Patrick and Shopping
    [APIO2014] [Uoj103] [Bzoj3676] Palindromes回文串 [Manacher,后缀数组]
    [Hdu3068]最长回文[Manacher]
    [hdu2222] [AC自动机模板] Keywords Search [AC自动机]
    [Bzoj3940] [AC自动机,USACO 2015 February Gold] Censor [AC自动机模板题]
    [Poj3261] [Bzoj1717] [后缀数组论文例题,USACO 2006 December Gold] Milk Patterns [后缀数组可重叠的k次最长重复子串]
    [Poj1743] [后缀数组论文例题] Musical Theme [后缀数组不可重叠最长重复子串]
    [UOJ#35] [UOJ后缀数组模板题] 后缀排序 [后缀数组模板]
    [Bzoj4196] [NOI2015] 软件包管理器 [树链剖分,线段树]
    [Bzoj4195] [NOI2015] 程序自动分析 [并查集,哈希,map] 题解
  • 原文地址:https://www.cnblogs.com/mrwh/p/11623759.html
Copyright © 2011-2022 走看看