Redux工程优化
视频教程:技术胖 Redux 免费教程
参考链接:技术胖 Redux 教程笔记汇总
本文搭配原文教程食用,风味更佳~!
Action Type 分离
写Redux Action的时候,我们写了很多Action的派发,产生了很多Action Types。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| inputChangeValue(e) { const action = { type: "input_change_value", value: e.target.value, } store.dispatch(action) }
addItem() { const action = { type: "add_item", } store.dispatch(action) }
deleteItem(index) { const action = { type: "delete_item", index, } store.dispatch(action) }
|
在项目管理中,不分离 action.type 会导致两个问题:
- Types不统一管理,不利于大型项目的复用,设置会长生冗余代码。
- 因为Action里的Type,一定要和Reducer里的type一一对应在,所以这部分代码或字母写错后,浏览器里并没有明确的报错,这给调试带来了极大的困难。
actionTypes.js
因此,我们需要将组件派发的 action.type
单独分离成一个 actionTypes.js
文件,actionTypes.js
文件放在 src/store/
目录下。
1 2 3 4 5 6 7 8 9 10
| /* 将 action.type 分离成一个单独的文件 (actionTypes.js) 1.分离后能精确定位错误原因 (原书写方法不会报错,难debug),避免名称写错难定位的问题 2.增强代码复用性:可以在多个组件引用 action.type 的变量 */ // 要 export 抛出文件接口(此文件为常量);常量要大写 // 其他组件使用时不要忘记 import export const INPUT_CHANGE_VALUE = "input_change_value" export const ADD_ITEM = "add_item" export const DELETE_ITEM = "delete_item"
|
同时,我们需要修改组件TodoList.js
以及 Reducer reducer.js
中的 action.type
引用。注意要在开头将 actionTypes.js
引入。
TodoList.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| import React, { Component } from 'react'; import "antd/dist/antd.css"; import { Input, Button, List } from "antd"; import store from './store/index';
import { INPUT_CHANGE_VALUE, ADD_ITEM, DELETE_ITEM } from './store/actionTypes'
class TodoList extends Component { constructor(props) { super(props); this.inputChangeValue = this.inputChangeValue.bind(this) this.addItem = this.addItem.bind(this) this.deleteItem = this.deleteItem.bind(this) this.state = store.getState()
this.storeChange = this.storeChange.bind(this) store.subscribe(this.storeChange) }
inputChangeValue(e) { const action = { type: INPUT_CHANGE_VALUE, value: e.target.value, } store.dispatch(action) }
addItem() { const action = { type: ADD_ITEM, } store.dispatch(action) }
deleteItem(index) { const action = { type: DELETE_ITEM, index, } store.dispatch(action) }
storeChange() { this.setState(store.getState()) }
render() { return ( <div> <div style={{ margin: "10px" }}> <Input placeholder={this.state.inputValue} style={{ width: "250px", marginRight: "10px" }} onChange={this.inputChangeValue} /> <Button type="primary" onClick={this.addItem} >添加</Button> </div> <div style={{ width: "325px", margin: "10px" }}> <List size="small" bordered dataSource={this.state.list} renderItem={(item, index) => { return (<List.Item onClick={() => { this.deleteItem(index) }}>{item}</List.Item>) }} /> </div> </div> ); } }
export default TodoList;
|
reducer.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| // reducer.js 中也不要忘记修改 action.type import { INPUT_CHANGE_VALUE, ADD_ITEM, DELETE_ITEM } from './actionTypes'
const defaultState = { inputValue: "Write Something", list: [ "第一天", "第二天", "第三天", ] }
export default (state = defaultState, action) => { if (action.type === INPUT_CHANGE_VALUE) { let newState = JSON.parse(JSON.stringify(state)) newState.inputValue = action.value return newState }
if (action.type === ADD_ITEM) { let newState = JSON.parse(JSON.stringify(state)) newState.list.push(state.inputValue) return newState }
if (action.type === DELETE_ITEM) { let newState = JSON.parse(JSON.stringify(state)) newState.list.splice(action.index,1) return newState }
return state }
|
管理 Redux Action
工程项目中各组件里有很多Action,并且分散才程序的各个地方,如果庞大的工程,这势必会造成严重的混乱。因此,在工程中通常将所有的Redux Action放到一个文件里进行管理。
我们通常通过以下步骤将 action
对象单独分离出来:
- 在
src/store/
目录下新建 actionCreators.js
文件。(还记得吗?Redux 官方工作流程中管理 Action 的就是 actionCreators)
- 将
action对象
写入 actionCreators.js
中,并以方法的形式(普通函数或箭头函数)抛出。
- 引入方法,替换原组件内的
action
对象。
为什么不直接抛出 action 对象?
因为事件函数可能会传递参数给 action 对象,因此需要用函数来接受并传递参数。
actionCreators.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import { INPUT_CHANGE_VALUE, ADD_ITEM, DELETE_ITEM } from './actionTypes'
export const inputChangeValueAction = (value) => ({ type: INPUT_CHANGE_VALUE, value, })
export const addItemAction = () => ({ type: ADD_ITEM, })
export const deleteItemAction = (index) => ({ type: DELETE_ITEM, index, })
|
TodoList.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| import React, { Component } from 'react'; import "antd/dist/antd.css"; import { Input, Button, List } from "antd"; import store from './store/index';
import { inputChangeValueAction, addItemAction, deleteItemAction } from "./store/actionCreators"
class TodoList extends Component { constructor(props) { super(props); this.inputChangeValue = this.inputChangeValue.bind(this) this.addItem = this.addItem.bind(this) this.deleteItem = this.deleteItem.bind(this) this.state = store.getState()
this.storeChange = this.storeChange.bind(this) store.subscribe(this.storeChange) }
inputChangeValue(e) { const action = inputChangeValueAction(e.target.value) store.dispatch(action) }
addItem() { const action = addItemAction() store.dispatch(action) }
deleteItem(index) { const action = deleteItemAction(index) store.dispatch(action) }
storeChange() { this.setState(store.getState()) }
render() { return ( <div> <div style={{ margin: "10px" }}> <Input placeholder={this.state.inputValue} style={{ width: "250px", marginRight: "10px" }} onChange={this.inputChangeValue} /> <Button type="primary" onClick={this.addItem} >添加</Button> </div> <div style={{ width: "325px", margin: "10px" }}> <List size="small" bordered dataSource={this.state.list} renderItem={(item, index) => { return (<List.Item onClick={() => { this.deleteItem(index) }}>{item}</List.Item>) }} /> </div> </div> ); } }
export default TodoList;
|