Redux相关
Redux概念简述
- Redux = Reducer + Flux
Redux的工作流程
- 首先,一个组件要去获取Store里的一些数据,然后要给Store说"我要获取数据了",这句话就是Action Creators,然后通过Action Creators后Store知道了这句话,但是不知道是什么意思,所以就要去Reducers查询到底应该给组件什么样的数据。
Redux 的核心API
createStore
: 创建store
store.dispatch
: 派发action, 传递到store
store.getState
: 获取store里所有的数据内容
store.subscribe
订阅store的改变, 只要store发生改变, 订阅这个store的函数就会被执行
Store 的创建
- 安装 Redux:
npm install redux
- 在src下创建store,再创建创世store与reducer,示例如下
从 Store 取数据显示出来
- store.getState()
| import React, { Component } from "react";
import store from "./store";
class TodoList extends Component {
constructor(props) {
this.state = store.getState()
}
... ...
}
export default TodoList
|
Action 和 Reducer 的编写(完成输入框状态值渲染、list新增、list删除)
| import React, { Component, Fragment } from "react";
import store from "./store";
import './style.css'
import TodoItem from "./TodoItem";
class TodoList extends Component {
// 构造方法,固定接收props
constructor(props) {
// 当props发生改变,render就会被重新执行
// 当父组件的render函数被运行时,它的子组件的render都将被重新运行
// 调用父类的构造函数
super(props);
this.state = store.getState()
this.handleInputChange = this.handleInputChange.bind(this)
this.handleStoreChange = this.handleStoreChange.bind(this)
// 自动订阅store,监听store的内容
store.subscribe(this.handleStoreChange);
}
render() {
return (
<Fragment>
<div>
<label htmlFor="insertArea">输入内容</label>
<input
id="insertArea"
className="input"
value={this.state.inputValue}
// 改变handleInputChange的this指向
onChange={this.handleInputChange.bind(this)}
// 构建一个引用,这个引用叫this.input,指向input指定当前input的dom节点
/>
<button onClick={this.handleBtnClick.bind(this)}>提交</button>
</div>
<ul>
{
// 渲染数据
this.state.list.map((item, index) => {
return (
<TodoItem
// 父组件向子组件传值、方法,子组件可以通过props调用
itemVal={item}
index={index}
del={this.handleItemDelete.bind(this)}
/>
)
})
}
</ul>
</Fragment>
)
}
// componentDidMount () {
// axios.get('/api/todolist')
// .then(() => {alert('succ')})
// .catch(() => {alert('error')})
// }
handleInputChange(e) {
const value = e.target.value;
const action = {
type: 'change_input_value',
value: value
}
store.dispatch(action)
// this.setState({
// inputValue: value
// });
}
handleStoreChange () {
this.setState(store.getState())
}
handleBtnClick() {
const value = this.state.inputValue
const action = {
type: 'change_child_value',
value: value
}
store.dispatch(action);
// this.setState({
// // es6 追加
// list: [...this.state.list, this.state.inputValue],
// // 提交后清空当前input
// inputValue: ''
// });
}
handleItemDelete(index) {
// immutable
// state 不允许做出任何改变
// 展开运算符 把this.state.list做了一份copy
// const list = [...this.state.list];
// list.splice(index, 1);
// this.setState({
// list: list
// });
// const value = this.state.list;
const action = {
type: 'del_child_value',
index: index
}
store.dispatch(action)
}
}
export default TodoList
|
| // 定义在reducer只有两个字段,后续传入到store store也就知道reducer存储内容的结构了
const defaultState = {
inputValue: '',
list: [],
index: '',
}
// state = defaultState 默认什么都不存储
// reducer 可以接收state,但是绝不能修改state
export default (state = defaultState, action) => {
// console.log(state, action)
/*
{inputValue: '', list: Array(0)}]:
{type: 'change_input_value', value: 'f'}
*/
if (action.type === 'change_input_value') {
// 执行一次深拷贝 然后修改深拷贝的值
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState;
}
if (action.type === 'change_child_value') {
const newState = JSON.parse(JSON.stringify(state));
newState.list.push(newState.inputValue);
newState.inputValue = '';
console.log('change_child_value:newState', newState)
/**
{
inputValue: ""
list: ['123', '321']
}
*/
return newState;
}
if (action.type === 'del_child_value') {
const newState = JSON.parse(JSON.stringify(state))
console.log(newState)
// console.log(newState, state)
newState.list.splice(action.index, 1);
return newState;
}
// state: 整个store存储的数据
return state
}
|
总结
react改变store里的数据,首先要开发一个Action,Action会通过dispatch方法传递给store,store再把之前的数据和action转发给Reducer,Reducer是个函数,它接收到了state和action之后做一些处理会返回一个新的state给到store,store用这个新的数据替换掉之前store里的数据,然后store数据发生改变的时候,react组件会感知(subscribe)到store发生了改变,这个时候它从store里重新取数据,更新组件的内容。页面就跟着发生变化了。
Redux 设计和使用的三项原则
store 必须是唯一的。
只有store 能改变自己的内容。
Reducer 必须是纯函数:纯函数是指,给定固定的输入,就一定会有固定的输出,而且不会有任何副作用。
番外
ActionTypes的拆分
提示
将枚举类型或字符串类型的变量单独定义到新的js文件中,通过 export const *** 记录,然后引用 const 名称使用。
使用actionCreator统一创建action
-
优化前
const value = this.state.inputValue
const action = {
type: 'change_child_value',
value: value
}
store.dispatch(action);
-
优化后