注意:此Demo使用了react官方脚手架和antd
一:目的
在react中组件与组件之间的通信很麻烦,于是借用redux进行第三方的通信
通过把数据存储在store里,实现各个组件间快速通信
二:工作流程
or
注:store是一个联系和管理。具有如下职责
-
维持应用的
state
; -
提供
getState()
方法获取 state -
提供
dispatch(action)
方法更新 state; -
通过
subscribe(listener)
注册监听器; -
通过
subscribe(listener)
返回的函数注销监听器。
准备工作1:创建store(具体安装参考redux官网)
import {createStore} from 'redux';
import reducer from './reducer';
const store = createStore(
reducer,
);
export default store;
准备工作2:创建reducer
const defaultState={
inputValue:'',
list:[]
};
//reducer可以接收state,但是绝不能修改state
export default (state=defaultState,action)=>{
return state;
}
流程1:传递action告诉store,store会自动转发给reducer
handleInputChange=(e)=>{
//告诉store,输入的类型和输入框中的值
const action={
type:'change_input_value',
value: e.target.value,
};
//把action传给store
store.dispatch(action);
//store自动传给reducer
};
流程2:reducer接收信息,并返回给store一个newState
export default (state=defaultState,action)=>{
//input
if (action.type==='change_input_value'){
const newState=JSON.parse(JSON.stringify(state));//简单的深拷贝
newState.inputValue=action.value;
return newState;
}
}
流程3:TodoList监听state的变化
constructor(props){
super(props);
this.state=store.getState();
//监听store里面的变化,只要一变化
//只要store里面的数据发生改变,则立即执行subscribe函数里的函数
store.subscribe(this.handleStoreChange)
}
handleStoreChange=()=>{
this.setState(store.getState());
// console.log('store change')
// 感知store发生变化之后,从store里获取最新的数据,然后进行设置
};
三:具体代码
1:结构图(使用了react官方脚手架)
2:index.js(入口文件)
import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList';
ReactDOM.render(<TodoList />, document.getElementById('root'));
3:TodoList.js
import React ,{Component}from 'react';
import 'antd/dist/antd.css'
import {Input,Button,List} from 'antd'
import store from './store/index';
class TodoList extends Component{
constructor(props){
super(props);
this.state=store.getState();//获取store里的所有关于state的数据
//监听store里面的变化,只要一变化
//只要store里面的数据发生改变,则立即执行subscribe函数里的函数
store.subscribe(this.handleStoreChange)
}
render(){
return(
<div style={{margin:'10px',marginLeft:'10px'}}>
<div>
<Input
value={this.state.inputValue}
placehoder="todo list "
style={{width:'300px'}}
onChange={this.handleInputChange}
/>
<Button
type= "primary"
onClick={this.handleBtnClick}
>提交</Button>
</div>
<List
style={{marginTop:'10px',width:'300px'}}
bordered
dataSource={this.state.list}
renderItem={(item,index) => (<List.Item onClick={this.handleItemDelet} >{item}</List.Item>)}//这个这个参考antd官网
/>
</div>
)
}
handleInputChange=(e)=>{
// console.log(e.target.value);//获取input的value值
//告诉store,输入的类型和输入框中的值
const action={
type:'change_input_value',
value: e.target.value,
};
//把action传给store
store.dispatch(action);
//store自动传给reducer
};
//reducer返回newState之后,store传递newState给组件
handleStoreChange=()=>{
this.setState(store.getState());
// console.log('store change')
// 感知store发生变化之后,从store里获取最新的数据,然后进行设置
};
//提交按钮(又一次流程)
handleBtnClick=()=>{
const action={
type:'add_todo_item'
};
store.dispatch(action);
};
//点击删除
handleItemDelet=(index)=>{
const action={
type:'delete_todo_item',
index:index,
};
store.dispatch(action);
}
}
export default TodoList;
4:store下的index.js
import {createStore} from 'redux';
import reducer from './reducer';
//1-store是唯一的
//2-只有store才能改变自己的内容(state)
//3-reducer必须是纯函数
const store = createStore(
reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
// /如果安装了redeux devtools扩展这个工具(谷歌商店里下载),则在控制台里使用这个方法(为了调试redux)
);
export default store;
补充:可以下载谷歌插件方便查看store
效果:
5:store下的reducer.js
const defaultState={
inputValue:'',
list:[]
};
//reducer可以接收state,但是绝不能修改state
// reducer必须是纯函数
//纯函数:给固定的输入,一定有固定的输出(不能有不固定的日期函数),不会有副作用(改变参数的值)
export default (state=defaultState,action)=>{
//input
if (action.type==='change_input_value'){
const newState=JSON.parse(JSON.stringify(state));//简单的深拷贝
newState.inputValue=action.value;
return newState;
}
//button
if (action.type==="add_todo_item"){
const newState=JSON.parse(JSON.stringify(state));//把老数据拷贝一份
newState.list.push(newState.inputValue);//在列表中新加输入框内容
newState.inputValue='';//点击提交之后,输入框清空
// console.log(newState);
return newState;//返回给store
}
//点击删除
if (action.type==='delete_todo_item'){
const newState=JSON.parse(JSON.stringify(state));
newState.list.splice(action.index,1);
return newState;
}
return state;
}
四:效果预览
五:整体结构优化
1:优化的目标
1.1:action的type由公共的actionTypes管理
const action={
// type:'add_todo_item'
type:ADD_TODO_ITEM
};
1.2:将action封装成对象,写在actionCreator.js文件里
//action封装之前
const action={
// type:'add_todo_item'
type:ADD_TODO_ITEM
};
// action封装之后
const action=getAddItemActiom();
store.dispatch(action);
export const getAddItemActiom=()=>({
type:ADD_TODO_ITEM,
});
2:目录结构
3.index.js
import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList';
ReactDOM.render(<TodoList />, document.getElementById('root'));
4.TodoList.js
import React ,{Component}from 'react';
import 'antd/dist/antd.css'
import {Input,Button,List} from 'antd'
import store from './store/index';
import {getInputChangeAction,getAddItemActiom,getDeleteItemAction}from './store/actionCreator';//从封装的actionCreator解构出自定义的函数
class TodoList extends Component{
constructor(props){
super(props);
this.state=store.getState();
//监听store里面的变化,只要一变化
//只要store里面的数据发生改变,则立即执行subscribe函数里的函数
store.subscribe(this.handleStoreChange)
}
render(){
return(
<div style={{margin:'10px',marginLeft:'10px'}}>
<div>
<Input
value={this.state.inputValue}
placehoder="todo list "
style={{width:'300px'}}
onChange={this.handleInputChange}
/>
<Button
type= "primary"
onClick={this.handleBtnClick}
>提交</Button>
</div>
<List
style={{marginTop:'10px',width:'300px'}}
bordered
dataSource={this.state.list}
renderItem={(item,index) => (<List.Item onClick={this.handleItemDelet} >{item}</List.Item>)}//这个这个参考antd官网
/>
</div>
)
}
handleInputChange=(e)=>{
// console.log(e.target.value);//获取input的value值
//告诉store,输入的类型和输入框中的值
// const action={
// // type:'change_input_value',
// type:CHANGE_INPUT_VALUE,//由公共常量代替,防止,字符串不一致
// value: e.target.value,
// };
const action=getInputChangeAction(e.target.value);
//把action传给store
store.dispatch(action);
//store自动传给reducer
};
//reducer返回newState之后,store传递newState给组件
handleStoreChange=()=>{
this.setState(store.getState());
// console.log('store change')
// 感知store发生变化之后,从store里获取最新的数据,然后进行设置
};
//提交按钮(又一次流程)
handleBtnClick=()=>{
// //action封装之前
// const action={
// // type:'add_todo_item'
// type:ADD_TODO_ITEM
// };
// action封装之后
const action=getAddItemActiom();
store.dispatch(action);
};
//点击删除
handleItemDelet=(index)=>{
// const action={
// // type:'delete_todo_item',
// type:DELETE_TODO_ITEM,
// index:index,
// };
// action封装之后
const action=getDeleteItemAction(index);
store.dispatch(action);
}
}
export default TodoList;
5.store/index.js
import {createStore} from 'redux';
import reducer from './reducer';
//1-store是唯一的
//2-只有store才能改变自己的内容(state)
//3-reducer必须是纯函数
const store = createStore(
reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
// /如果安装了redeux devtools扩展这个工具(谷歌商店里下载),则在控制台里使用这个方法(为了调试redux)
);
export default store;
6.store/reducer.js
import {CHANGE_INPUT_VALUE,ADD_TODO_ITEM,DELETE_TODO_ITEM} from './actionTypes';//引入常量
const defaultState={
inputValue:'',
list:[]
};
//reducer可以接收state,但是绝不能修改state
// reducer必须是纯函数
//纯函数:给固定的输入,一定有固定的输出(不能有不固定的日期函数),不会有副作用(改变参数的值)
export default (state=defaultState,action)=>{
//input
if (action.type===CHANGE_INPUT_VALUE){
const newState=JSON.parse(JSON.stringify(state));//简单的深拷贝
newState.inputValue=action.value;
return newState;
}
//button
if (action.type===ADD_TODO_ITEM){
const newState=JSON.parse(JSON.stringify(state));//把老数据拷贝一份
newState.list.push(newState.inputValue);//在列表中新加输入框内容
newState.inputValue='';//点击提交之后,输入框清空
// console.log(newState);
return newState;//返回给store
}
//点击删除
if (action.type===DELETE_TODO_ITEM){
const newState=JSON.parse(JSON.stringify(state));
newState.list.splice(action.index,1);
return newState;
}
return state;
}
7.store/actionTypes.js
export const CHANGE_INPUT_VALUE='change_input_value';
export const ADD_TODO_ITEM='add_todo_item';
export const DELETE_TODO_ITEM='delete_todo_item';
8.store/actionCreator.js
//用actionCreator创建统一的action
import {CHANGE_INPUT_VALUE,ADD_TODO_ITEM,DELETE_TODO_ITEM} from './actionTypes';//引入常量
//为了封装 const action={
// // type:'add_todo_item'
// type:ADD_TODO_ITEM
// };
export const getInputChangeAction=(value)=>({
type:CHANGE_INPUT_VALUE,
value:value,
});
export const getAddItemActiom=()=>({
type:ADD_TODO_ITEM,
});
export const getDeleteItemAction=(index)=>({
type:DELETE_TODO_ITEM,
index:index,
});