【React自制全家桶】九、Redux入手
一、React项目中为什么要用Redux
上图:
左图当使用纯React开发稍微大点的项目,因为React数据是瀑布式的,只能通过父子组件传递数据,所以实现关系不大的两React的组件之间的数据传递就会让你非常难受,操作起来非常复杂。如右图,由此应运而生了Redux数据流框架,专门解决数据流问题,
Redux的基本原理就是React的所有组件涉及到的数据全部都存储在共用的Store中,这样所有组件都可以通过Store来改动数据和获取数据,非常方便。
二、Redux安装
在已经安装yarn的前提下
yarn add redux
三、Redux工作流讲解
先上图:
为了方便理解,我将一个redux的操作流程视为从图书馆取书的流程:
1、React Components(借书人)
2、说借一本《React全栈》书(Action Creations就是代表需要进行的操作)
3、Store(图书馆管理员)听到了这句话
4、从reducers(记书本)中查询书在哪放着
5、Store(图书馆管理员)查到(即reducers返回newState)
6、Store(图书馆管理员)将书交给React Components(借书人)(即:将改动后的state发给React Components(借书人))
四、Redux使用入门
1、使用谷歌浏览器下载浏览器rudux插件(建议开启科学上网后下载安装)
2、在src目录下创建store文件夹
3、在store文件夹下创建index.js文件作为redux的入口文件
import {createStore} from 'redux';
// 引入reducer
import reducer from './reducer'; const store = createStore(
reducer,
// 显示redux调试工具
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
); export default store;
4、在store文件夹下创建reducer.js文件作为数据
import {CHANGE_INPUT_VALUE , ADD_TODO_ITEM , DELETE_TODO_ITEM} from './actionTypes'; const defaultState = {
inputValue : "",
list: []
}; //reducers可以接收state但是绝不能修改state
//reducers不能有异步操作也不能有与时间相关的操作,也不能对接收的参数进行修改
//返回纯函数,纯函数指的是:给定固定输入,则输出固定,而且不会有任何副作用
export default (state = defaultState,action) => {
// state是上一个store中存储的数据,action是用户发过来的操作请求
// 1、JSON.parse()用于从一个字符串中解析出json对象
// 2、JSON.stringify()用于从一个对象解析出字符串
if (action.type === CHANGE_INPUT_VALUE) {
// state深拷贝
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState;
}
if (action.type === ADD_TODO_ITEM) {
// state深拷贝
const newState = JSON.parse(JSON.stringify(state));
newState.list.push(newState.inputValue);
newState.inputValue = '';
return newState;
}
if (action.type === DELETE_TODO_ITEM) {
// state深拷贝
const newState = JSON.parse(JSON.stringify(state));
newState.list.splice(action.index, 1);
return newState;
}
return state;
}
5、核心组件中导入store
import React,{Component} from 'react';
import 'antd/dist/antd.css';
import {Input, Button, List} from 'antd';
import store from './store/index';
import {getInputChangeAction, getAddItemAction, getDeleteItemAction} from './store/actionCreators'
// import {CHANGE_INPUT_VALUE , ADD_TODO_ITEM , DELETE_TODO_ITEM} from './store/actionTypes'; class TodoList extends Component{ constructor(props){
super(props);
this.state = store.getState();
this.handleInputChange = this.handleInputChange.bind(this);
this.handleStoreChange = this.handleStoreChange.bind(this);
this.handleBtnClick = this.handleBtnClick.bind(this);
// 监听store中数据的变化,改变则通过handleStoreChange()函数重新渲染
store.subscribe(this.handleStoreChange)
} render(){
return(
<div style={{margin:'30px'}}>
<div>
<Input
type="text"
value={this.state.inputValue}
placeholder='todo info'
style={{width:'300px',marginRight:'10px'}}
onChange={this.handleInputChange}
/>
<Button type="primary" onClick={this.handleBtnClick}>提交</Button>
</div>
<div>
<List
style={{width:'300px',marginTop:'10px'}}
bordered
// 数据源
dataSource={this.state.list}
renderItem={(item,index) => (<List.Item onClick={this.handleItemDelete.bind(this,index)}>{item}</List.Item>)}
/>
</div>
</div>
)
} // 输入框改变
handleInputChange(e){
const action = getInputChangeAction(e.target.value);
// 将action派发给store
store.dispatch(action);
} // 数据重新获取并渲染
handleStoreChange(){
// store.getState()从store中重新取数据
// this.setState()更新数据
this.setState(store.getState())
} // 点击后增添数据
handleBtnClick(){
// 创建action对象
const action = getAddItemAction();
// 将action发给store
store.dispatch(action);
} handleItemDelete(index){
const action = getDeleteItemAction(index);
store.dispatch(action);
} } export default TodoList;
6、升级——store中创建actionCreators
import {ADD_TODO_ITEM, CHANGE_INPUT_VALUE, DELETE_TODO_ITEM} from "./actionTypes"; export const getInputChangeAction = (value) => ({
type : CHANGE_INPUT_VALUE,
value
}); export const getAddItemAction = () => ({
type : ADD_TODO_ITEM
}); export const getDeleteItemAction = (index) => ({
type : DELETE_TODO_ITEM,
index
});
7、升级——store中创建actionTypes
export const CHANGE_INPUT_VALUE = 'change_input_value';
export const ADD_TODO_ITEM = 'add_todo_item';
export const DELETE_TODO_ITEM = 'delete_todo_item';
最新文章
- Atitit. 构造ast 语法树的总结attilax oao&#160;1. Ast结构树形12. ast view (自是个160k的jar )22.1. 多条语句ast结构22.2. 变量定义&#160;int&#160;b,c;&#160;的ast结构22.3. 方法调用meth1(a=1,b=2,c=3);&#160;&#160;的ast结构23. 误解的问题33.1. 语法书子能是个二叉树,实际上多叉树越好..33.2. 非要不个ast放到个s
- android: SharedPreferences实现记住密码功能
- App 卸载记录
- BZOJ3789 : 扫雪车
- ThinkPHP多表操作
- HDU 3966 Aragorn&#39;s Story (树链点权剖分,成段修改单点查询)
- 你不知道的Eclipse用法:使用Allocation tracker跟踪Android应用内存分配
- Android在未来对 Java 8 特性的支持
- 【Unity3D技术文档翻译】第1.4篇 AssetBundle 依赖关系
- ASP.NET Core + Docker + Jenkins + gogs + CentOS 从零开始搭建持续集成
- svn 回退/更新/取消至某个版本命令详解
- awk字符串函数及其意义
- Redis详解(五)------ redis的五大数据类型实现原理
- java新知识系列 一
- Django 安装配置
- 关于iptables添加规则不生效的问题
- LeetCode 104. Maximum Depth of Binary Tree C++ 解题报告
- 学习笔记CB004:提问、检索、回答、NLPIR
- 蓝桥杯—ALGO-18 单词接龙(DFS)
- ubuntu16.04中启动anaconda图形化界面
热门文章
- innodb存储引擎之内存
- 【异常】lockfile.AlreadyLocked: ~/airflow/airflow-scheduler.pid is already locked
- js基本事件
- Java ==和equals的区别
- 8.JVM技术_JVM参数列表
- 版本控制工具 svn 一
- 【两种方式】vuex 如何监听页面状态的变化
- web开发中的支付宝支付和微信支付
- mongo批量插入问题(insert_many,bulk_write),spark df转json传入mongo
- JS 函数基础