Action Creator:action创建函数是将action作为一个函数进行封装,为了在store和view中进行方便调用
actionCreator = { // changeName是一个函数,是actionCreator的一个方法. // 调用这个方法,就会返回一个对象,这个对象就是action changeName: (name) => ({ type: CHANGENAME, name: name }), changeAge: (age) => ({ type: CHANGEAGE, age: age }), }
ActionTypes:用来管理整个项目所有的action的type
export const CHANGEAGE = 'changeAge'; export const CHANGENAME = 'changeName';
import {CHANGEAGE, CHANGENAME} from './type' // 修改数据的纯函数:reducer const reducer = (state=initState, action)=>{ // action就是一个js的obj,一定会有一个属性叫type:{type: xxx, name: 'Jack'} switch (action.type) { case CHANGENAME: // 返回一个对象,作为新的state return { ...state, name: action.name } case CHANGEAGE: return { ...state, age: action.age } default: return state } }
import {CHANGEAGE, CHANGENAME} from '../store/type' actionCreator = { // changeName是一个函数,是actionCreator的一个方法. // 调用这个方法,就会返回一个对象,这个对象就是action changeName: (name) => ({ type: CHANGENAME, name: name }), changeAge: (age) => ({ type: CHANGEAGE, age: age }), }
将type.js中的变量导入到各个组件以及store中,保证整个项目的每个action的type属性都使用这里的变量,提高项目的可维护性。
reducer的拆分与合并
通过modules拆分不同模块的代码,再通过combineReducers方法将他们联合,最终创建store
// 导入不同模块中的内容 import orderReducer from './modules/order' import userReducer from './modules/user' // 通过combineReducers方法,合并两个模块中的reducer let rootReducer = combineReducers({ order: orderReducer, user: userReducer, }) const store = createStore(rootReducer); export default store
其中,info模块代码如下,user模块类似,详见代码部分。
// 初始化数据 const initState = { // 订单列表 info: {} } // 统一处理action的type const type = { CHANGEINFO: 'changeInfo' } // 统一处理action,这里会生成所有的action const actions = { changeList: (info) => ({type: type.CHANGEINFO, info}) } const reducer = (state = initState, action)=> { switch (action.type) { case type.CHANGEINFO: return { ...state, info: action.info } default: return state } } export default reducer;
redux devTools调试工具:类似vue-devtools,可以在浏览器中看到当前数据状态等信息
-
打开chrome->扩展程序->选择下载好的devTool工具(地址:Releases · zalmoxisus/redux-devtools-extension · GitHub,选择firefox即可)
-
安装依赖包 cnpm i redux-devtools-extension --save-dev
-
在代码中使用
import {composeWithDevTools} from 'redux-devtools-extension' const store = createStore(rootReducer,composeWithDevTools(applyMiddleware())) export default store
react-redux
react-redux是redux的官方react绑定库,即为react准备的比较特殊的redux版本。它能够使你的React组件从redux store中读取数据,并且向store分发actions以更新数据 作用:为了方便组件关联状态
-
安装 cnpm i react-redux --save
-
在src/index.js中使用
// 全局引入store,方便全局使用 import store from './store' // 引入Provider组件,将store放在全局使用 import { Provider } from 'react-redux' ReactDOM.render( // 使用Provider组件,包着其他内容,store就可以全局使用了. // 通过父传子的形式,将store的数据传给App <Provider store={store}> {/* 使用BrowserRouter组件包裹着App组件 */} <BrowserRouter> <App /> </BrowserRouter> </Provider>, document.getElementById('root') );
-
在组件中使用 react-redux 提供connect方法,用于从 UI 组件生成容器组件。react-redux将组件分成两类:容器型组件(有数据和逻辑)、UI组件(没有数据和逻辑,只是呈现内容)
let ReactRedux = connect(mapStateToProps, mapDispatchToProps)(ReactReduxUI) // ReactReduxUI是ui组件,通过connect()使他变成了容器型组件(ReactRedux),暴露容器性组件出去 export default ReactRedux
-
容器型组件VS展示型组件
容器型组件 | 展示型组件 | |
---|---|---|
关注点 | 逻辑[取数据,更新数据] | UI的展现 |
对redux是否感知 | 是 | 否 |
读数据 | 从redux的store 中获取 | 从props中获取 |
写数据 | 发送redux actions | 调用props的回调 |
如何创建 | 通过react-redux connect创建 | 手写 |
-
mapStateToProps类似vuex中的mapState和mapGetters,将数据映射到组件中,用来获取数据
-
mapDispatchToProps类似vuex中的mapAction和mapMutation,将修改数据的方法映射到组件中,用来触发数据的修改
redux高阶
-
bindActionCreators:将单个或多个ActionCreator转化为dispatch(action)的函数集合形式,统一返回
// 导入bindActionCreators,将各个action一起导入 import {bindActionCreators} from 'redux' const mapDispatchToProps = (dispatch) => ({ changeInfo: (info) => dispatch(userAction.changeInfo(info)), // changeList: (list) => dispatch(orderAction.changeList(list)), // addList: (list) => dispatch(orderAction.addList(list)), // delList: (list) => dispatch(orderAction.delList(list)), // 将修改数据的方法一次性全部导入(订单模块的方法全部导入) orderAction: bindActionCreators(orderAction, dispatch) })
Redux中间件
Redux middleware 提供了一个分类处理 action 的机会。在 middleware 中,我们可以检阅每一个流过的 action,并挑选出特定类型的 action 进行相应操作,以此来改变 action。
自己封装中间件
// store/index.js // 1.封装中间件 const logger = store=>next=>action=>{ console.log('调用dispatch的action',action); let result = next(action) console.log('调用dispatch后的state为',store.getState()); return result } const store = createStore(rootReducer,composeWithDevTools(applyMiddleware(logger)))
redux-logger中间件,使用action的中间件,一般放在参数的最后一位
下载 cnpm i redux-logger --save
引入 // 引入redux-logger import {logger} from 'redux-logger'
使用
store/index.js const store = createStore(rootReducer,composeWithDevTools(applyMiddleware(logger))) export default store
项目目录设计
-
按照类型划分
actions #action creator action1.js action2.js reducers #reducer函数 reducer1.js reducer2.js containers #容器型组件 container1.jsx container2.jsx components #展示型组件 components1.js components2.js
总结:如果需要修改一个功能,则需要修改好几个文件.
-
按照功能设计
feature1 #功能1 components #展示型组件 compoents1.jsx index.j #容器型组件 reducer.js #reducer函数 actrions.js #action creator feature2 #功能2 components #展示型组件 compoents2.jsx index.j #容器型组件 reducer.js #reducer函数 actrions.js #action creator
总结:如果按照功能设计来来分.数据会存在重复使用,会造成代码冗余的效果
-
ducks设计模式 ducks模式将reducer,action Type和actions绑定到同一个目录中.导致减少样板.
src -components #公共组件 pages Order index.js #容器型组件 components Order.jsx #展示型组件 User index.js #容器型组件 components User.jsx #展示型组件 store index.js #store状态对象 modules Order.js #子模块:state, action Types action Creator, reducer, action selector User.js #子模块:state, action Types action Creator, reducer, action selector