react redux 二次开发流程
程序员文章站
2023-11-13 13:53:58
在一个大项目中如何引入redux及其相关技术栈(react-redux redux-thunk redux-immutable ),已经成为react前端工程师不可或缺的技能,下面通过实现一个简单的todolist效果,来介绍相关流程 1.引入redux进行应用数据管理,安装相关依赖 yarn ad ......
在一个大项目中如何引入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)
参考文档
类似这样
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