写Redux Action的时候,我们写了很多Action的派发,产生了很多Action Types,如果需要Action的地方我们就自己命名一个Type,会出现两个基本问题:
(1)这些Types如果不统一管理,不利于大型项目的复用,设置会产生冗余代码。
(2)因为Action里的Type,一定要和Reducer里的type一一对应在,所以这部分代码或字母写错后,浏览器里并没有明确的报错,这给调试带来了极大的困难。
技巧一:
把Action Type单独拆分出一个文件。在src/store文件夹下面,新建立一个actionTypes.js文件,然后把Type集中放到文件中进行管理。
export const CHANGE_INPUT = 'changeInput';
export const ADD_ITEM = 'addItem';
export const DELETE_ITEM = 'deleteItem';
技巧二:
目前ToDoList组件里有很多Action,并且分散在程序的各个地方,如果庞大的工程,这势必会造成严重的混乱,就把所有的Redux Action放到一个文件里进行管理。
编写actionCreators.js文件
在src/store文件夹下面,建立一个心的文件actionCreators.js,先在文件中引入上节课编写actionTypes.js文件。
import { CHANGE_INPUT, ADD_ITEM, DELETE_ITEM } from './actionTypes';
export const changeInputAction = (value) => ({
type: CHANGE_INPUT,
value
})
export const addItemAction = () => ({
type: ADD_ITEM,
})
export const deleteItemAction = (index) => ({
type: DELETE_ITEM,
index
})
改写之后reducer.js文件
import { CHANGE_INPUT, ADD_ITEM, DELETE_ITEM } from './actionTypes';
const defaultState = {
inputValue:'Write Something',
list:[
'早8点开晨会,分配今天的代码任务',
'早9点和项目经理开需求沟通会',
'晚5点组织人员进行Review代码'
]
};
export default( state = defaultState, action ) => {
console.log(state,action);
//Reducer里只能接收state,不能改变state
if(action.type === CHANGE_INPUT){
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(newState.inputValue);
newState.inputValue=''; //增加完设置input内容为空
return newState;
}
if(action.type === DELETE_ITEM){
let newState=JSON.parse(JSON.stringify(state)); //深拷贝
newState.list.splice(action.index,1);
return newState;
}
return state;
}
TodoList.js文件
import React, {Component} from 'react';
import 'antd/dist/antd.css';
import {Input, Button, List} from 'antd';
import store from './store';
import {changeInputAction, addItemAction, deleteItemAction} from './store/actionCreators';
class TodoList extends Component {
constructor(props){
super(props);
this.state=store.getState(); //store.getState()方法可以拿到reducer.js中的数据
this.changeInputvalue=this.changeInputvalue.bind(this);
this.storeChange=this.storeChange.bind(this);
this.clickBtn=this.clickBtn.bind(this);
store.subscribe(this.storeChange); //如果想要state的状态发生变化,订阅模式必须写上
}
changeInputvalue(e){
const action=changeInputAction(e.target.value);
store.dispatch(action);
}
clickBtn(){
const action=addItemAction();
store.dispatch(action);
}
deleteItem(index){
const action=deleteItemAction(index);
store.dispatch(action);
}
storeChange(){
this.setState(store.getState());
}
render(){
return(
<div style={{margin:'10px'}}>
<div>
<Input
placeholder={this.state.inputValue}
style={{width:'250px', marginRight:'10px'}}
onChange={this.changeInputvalue}
value={this.state.inputValue}
/>
<Button type="primary"
onClick={this.clickBtn}>增加</Button>
<div style={{margin:'10px',width:'300px'}}>
<List
bordered
dataSource={this.state.list}
renderItem={(item,index)=>(<List.Item onClick={this.deleteItem.bind(this,index)}>{item}</List.Item>)}
/>
</div>
</div>
</div>
)
}
}
export default TodoList;
Redux填三个坑:
(1)store必须是唯一的,多个store是坚决不允许,只能有一个store空间
现在看TodoList.js的代码,就可以看到,这里有一个/store/index.js文件,只在这个文件中用createStore()方法,声明了一个store,之后整个应用都在使用这个store。
(2)只有store能改变自己的内容,Reducer不能改变
很多新手小伙伴会认为把业务逻辑写在了Reducer中,那改变state值的一定是Reducer,其实不然,在Reducer中我们只是作了一个返回,返回到了store中,并没有作任何改变。
Reudcer只是返回了更改的数据,但是并没有更改store中的数据,store拿到了Reducer的数据,自己对自己进行了更新。
(3)Reducer必须是纯函数
纯函数定义:如果函数的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部任何状态或数据的变化,必须只依赖于其输入参数。
reducer.js返回结果,是完全由传入的参数state和action决定的,这就是一个纯函数。这个在实际工作中是如何犯错的?比如在Reducer里增加一个异步ajax函数,获取一些后端接口数据,然后再返回,这就是不允许的(包括你使用日期函数也是不允许的),因为违反了调用参数相同,返回相同的纯函数规则。