react全局状态管理
先来看一下Redux的流程图
基本概念
- Store: 保存数据的地方,可以看成一个容器,一个应用只能有一个Store
- Store: 对象包含所有数据。如果想要得到某个时点的数据,就要对Store生成快照。这种时点的数据集合,就叫做State
- Action: 是一个对象。其中的type属性是必须的,表示Action的名称(下面会有例子),其他属性可以自由设置
- Action Creator: View要发送多少种消息,就会有多少种Action。如果都手写会很麻烦,可以定义一个函数来生成Action,这个函数就叫 actionCreator
- store.dispatch(): 是View发出Action的唯一方法
- Reducer: 是一个纯函数。 Store收到Action以后,必须给出一个新的State,这样View才会发生变化。这种State的计算过程就叫做Reducer
- store.subscribe(): Store允许使用
store.subscribe()
方法设置一个监听函数,一旦State发生变化,就会自动执行这个函数。
下面开始小例子
文件结构
需要用到的插件redux
- 先安装redux
npm install redux --save
代码 - 代码中有详细的注释
- app.js中只引入了Box组件,并且使用 所以就不做展示
Box.js
import React, { Component, Fragment } from "react";
import Son1 from './Son1'
import Son2 from './Son2'
// Box 是容器组件 - 负责展示
function Box () {
return (
<Fragment>
<Son1></Son1>
<hr/>
<Son2></Son2>
</Fragment>
)
}
export default Box
Son1.js
import React, { Component } from "react";
// 在需要使用到数据的组件中引入Store
import store from './Store/store'
import actionCreator from './Store/actionCreator'
class Son1 extends Component {
componentDidMount() {
// 使用subscribe监听reducer的改动.只要reducer中数据改变就会触发
store.subscribe(() => {
// 使用setState中只放一个空对象会更新所有的数据
// 目的就是触发render的执行, 来重新渲染页面, 让页面的数据发生改变
this.setState({})
})
}
render () {
// store下面有一个方法: getState() 获取到reducer下return的数据
/* store组件中使用了reducer, 并返回了新的reducer
reducer中返回的是state中的数据,
*/
let { name, age } = store.getState()
return (
<div>
<h3>Son1 子组件</h3>
<p>name: {name}</p>
<p>age: {age}</p>
<button
onClick={() => {
/* 调用actionCreator里面的changeName方法
但是只调用这个方法数据是会改变, 但是页面数据不会
改变
*/
actionCreator.changeName()
}}
>修改名字</button>
</div>
)
}
}
export default Son1
Son2.js: 和Son1.js几乎一样, 除了方法外
import React, { Component } from "react";
import store from './Store/store'
import actionCreator from "./Store/actionCreator";
class Son2 extends Component {
componentDidMount () {
store.subscribe(() => {
this.setState({})
})
}
render () {
let { name, age } = store.getState()
return (
<div>
<h3>Son2 子组件</h3>
<p>name: {name}</p>
<p>age: {age}</p>
<button
onClick={() => {
actionCreator.changeAge(25)
}}
>修改年龄</button>
</div>
)
}
}
export default Son2
store.js
// 从redux中引入createStore
/*
createStore 接受reducer作为参数,生成新的Store.
以后每当store.dispatch发送过来一个新的Action就会自动
调用reducer, 得到一个新的State
*/
import { createStore } from 'redux'
import reducer from './reducer' // reducer组件
let Store = createStore(reducer) // 生成一个新的Store
export default Store
state.js: 用来存储全局共享数据,这个例子需要用到的数据比较少。所以比简陋
// State 全局状态管理数据
export default {
name: '韩梅梅',
age : 18
}
reducer.js
// reducer
/*
reducer 本质是一个函数, 所以直接直接导出一个函数
这个函数接受两个参数
prevState: 修改前的数据
actions: 是一个对象, 里面放着很多方法.
*/
import State from './state'
/* 给prevState一个默认值: State
为什么不直接把State作为参数?
修改数据的时候只修改prevState, 不修改State中的数据
*/
export default (prevState = State, actions) => {
// 创建一个新的数据, 赋值prevState
let newData = prevState
// 数据的修改
// reducer 组件中接收到actionCreator中的action, 并解构出里面的属性
let { type, payload } = actions
// 使用switch方法, 判断调用的是哪个方法. 这时候就需要使用到type标识
switch (type) {
case 'CHANGE_NAME': // 判断type标识
newData.name = payload // 修改newData中的name为action中传来的数据
break;
case 'CHANGE_AGE':
newData.age = payload
break;
default:
break;
}
// 返回的数据是修改后的数据, 也是getState()方法获取的数据
return newData
}
actionCreator.js
// actionCreator 本质是一个对象. 这个对象里面有很多的方法
// 哪里需要调用这里面的方法, 就在哪个组件中引入actionCreator
import store from './store'
export default {
changeName () { // 修改name的方法
let action = { // action对象
type: 'CHANGE_NAME', // type 标识: 必须的属性, 固定属性只能是type
payload: '李雷雷' // 这是传递数据的参数
}
/* store.dispatch 是 View 发出 Action 的唯一方法。
接受一个 Action 对象作为参数,将它发送出去。
*/
store.dispatch(action)
},
changeAge (age) {
let action = {
type: 'CHANGE_AGE',
payload: age // 可以使用参数
}
store.dispatch(action)
}
}
效果