React 16 学习笔记(一)使用 Redux react-redux TodoList
使用create-react-app创建React项目
在指定目录使用如下命令创建项目todolist
create-react-app todolist
安装redux
yarn add redux
安装react-redux
yarn add react-redux
修改目录
剔除不需要的文件如图:
创建存储store
创建一个store目录,store中创建两个文件index,js和reducer.js
reducer.js
const defaultState={
inputValue:'',
list:[]
};
export default (state=defaultState, action) => {
return state
}
index.js
import { createStore } from "redux";
import reducer from "./reducer";
const store = createStore(reducer);
export default store;
修改index.js
Provider 功能是使被 包裹的TodoList组件使用react-redux
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import TodoList from './TodoList';
import store from './store'
const App = (
<Provider store={store}>
<TodoList/>
</Provider>
);
ReactDOM.render(<App />, document.getElementById('root'));
创建TodoList.js
class TodoList extends Component{
render() {
return (
<Fragment>
<input />
<button>提交</button>
</Fragment>
)
}
}
const mapStateToProps = (state)=>{
return {
inputValue: state.inputValue,
list:state.list,
}
};
const mapDispatchToProps=(dispatch)=>{
return {
}
};
export default connect(mapStateToProps,mapDispatchToProps)(TodoList);
修改input框value属性
input 值定义为inputValue,onChang事件,绑定一个InputChange方法
<input value={inputValue} onChange={this.props.InputChange}/>
在mapDispatchToProps中构造InputChange方法
这里需要定义一个type,用于区别传递的是哪个方法的action,通过 dispatch(action);直接将action传递给reducer
const mapDispatchToProps=(dispatch)=>{
return {
handleInputChange(e) {
const action = {
type:'CHANGE_INPUT_VALUE',
value:e.target.value
};
dispatch(action);
},
}
};
reducer接受传送过来的action
reducer不能直接修改store,因此需要先深拷贝一份store中的state,newState 中的inputValue修改后,将newState返回给store,store自动修改自己的数据
reducer.js
export default (state = defaultState, action) => {
if (action.type === 'CHANGE_INPUT_VALUE') {
const newState = JSON.parse(JSON.stringify(state)); // 拷贝一份
newState.inputValue = action.value;
return newState;
}
return state
}
输入的数据存入list,并显示
将上一步骤已修改的inputValue值,通过点击按钮,添加到list中。list通过map()方法循环显示在页面上
为按钮点击事件绑定方法
<button onClick={this.props.handleClick}>提交</button>
在mapDispatchToProps中构造handleClick方法
这里只需要传递一个type给reducer就可以了,不需要再讲inputValue进行传递,因为上步骤中已经修改好store中inputValue的值,直接使用就可以
handleClick(){
const action={
type: 'CLICK_BUTTON',
};
dispatch(action);
},
reducer接受传送过来的action
if (action.type === 'CLICK_BUTTON') {
const newState = JSON.parse(JSON.stringify(state));
newState.list.push(newState.inputValue);
newState.inputValue = '';//起到清空页面input框输入值
return newState;
}
页面显示list中的数据
map需要一个key值,使用index;
{
this.props.list.map((item,index)=>{
return (
<li key={index} >{item}</li>
)
})
}
添加点击删除功能
删除list中的某个值,需要知道这个值所对应的下标,需要将index传递给一个方法。bind()可以向方法传递参数,但是参数不能是第一个位置。,为li标签绑定一个点击事件,通过bind()给方法传递index参数
li标签绑定事件方法
<li key={index} onClick={deleteItem.bind(this,index)}>{item}</li>
在mapDispatchToProps中构造deleteItem方法
deleteItem(index){
const action={
type:'DELETE_ITEM',
index
};
dispatch(action);
},
reducer接受传送过来的action
splice删除对应index的list元素
if (action.type === 'DELETE_ITEM') {
const newState = JSON.parse(JSON.stringify(state));
newState.list.splice(action.index,1);
return newState;
}
代码优化
优化主要在两个方面:
一、todolist组件中不含有复杂逻辑,只有一个render()函数,改写为UI组件
二、ActionTypes进行拆分
首先拆分ActionTypes,创建actionTypes.js,需要对TodoList.js 和reducer.js进行修改
export const CHANGE_INPUT_VALUE = 'change_input_value';
export const CLICK_BUTTON = 'click_button';
export const DELETE_ITEM = 'delete_item';
TodoIist.js
import React,{ Fragment } from 'react';
import { connect } from 'react-redux';
import {CHANGE_INPUT_VALUE,CLICK_BUTTON,DELETE_ITEM} from './store/actionTypes'
const TodoList= (props)=>{
const {inputValue,handleInputChange,handleClick,list,deleteItem} = props;
return (
<Fragment>
<input value={inputValue} onChange={handleInputChange}/>
<button onClick={handleClick}>提交</button>
{
list.map((item,index)=>{
return (
<li key={index} onClick={deleteItem.bind(this,index)}>{item}</li>
)
})
}
</Fragment>
)
};
const mapStateToProps = (state)=>{
return {
inputValue: state.inputValue,
list:state.list,
}
};
const mapDispatchToProps=(dispatch)=>{
return {
handleInputChange(e) {
const action = {
type:CHANGE_INPUT_VALUE,
value:e.target.value
};
dispatch(action);
},
handleClick(){
const action={
type: CLICK_BUTTON,
};
dispatch(action);
},
deleteItem(index){
const action={
type:DELETE_ITEM,
index
};
dispatch(action);
},
}
};
export default connect(mapStateToProps,mapDispatchToProps)(TodoList);
总结
到此完成了全部代码,Redux需要注意:reducer不能直接修改store中的数据,需要先深拷贝,修改,再返回给store,同时reducer必须是一个纯函数,源代码