父子组件来回传 而兄弟组件无能为力 因此需要redux全局托管数据
redux 是一种数据管理模式 不仅仅可以用于react 还可以配合其他类库或框架使用 使用redux托管 redux会导出一个store 其中包含获取状态的方法 以及变更状态的方法
- 安装 redux
yarn add redux --save
- 创建store 需要使用redux 的 createStore方法 使用前需要导入
import {createStore} from 'redux'
- create创建store 需要reducer函数 **使用redux不能直接修改状态 需要定义修改状态的函数 这个函数称为reducer **
- reducer 函数会接收两个参数
- state 是redux 托管的数据对象 在创建reducer时给state设置默认值 就是state的初始值
- action 是修改状态的具体的动作及修改状态需要的参数 是一个带有type字段的对象{type:'ADD',...payload},而reducer的作用就是根据不同的action.type返回一个新的状态对象 使用reducer首先需要返回一个默认状态
function reducer(state = { num: 0 }, action) {
// state 就是当前 redux 托管的数据对象,在创建 reducer 时给 state 设置的默认值就是 state 的初始值
// action 是修改状态具体的动作以及修改状态需要的参数,是一个带有 type 字段的对象 { type: 'ADD', ...payload } ,而 reducer 的作用就是根据不同的 action.type 返回一个新的状态对象
switch (action.type) {
case 'ADD':
return {
num: state.num + action.amount
}
case 'MINUS':
return {
num: state.num - action.amount
}
}
// 使用 reducer 首先需要返回一个默认状态
return state
}
let store = createStore(reducer)
export default store
- 在组件中导入store
- store.getState() 初始化state
- 当修改数据时 需要派发行动 dispath action store.dispatch({type:'ADD',amount:12}), dispatch执行的传递对象 就是action action对象会传递给reducer函数的第二个参数
- 若需要数据修改更新视图 需要订阅这个数据发生变化后的事件 若想修改视图就更新state 在组件挂载的钩子中的订阅
- 订阅后会有取消订阅的需要 订阅函数会返回取消订阅的函数 在组件将要销毁的钩子中执行取消订阅的操作
- 导入
import store from '../store'
1. 使用store.getState() 初始化state
constructor(props,context){
super()
this.state = {
num:store.getState().num
}
}
2. store.dispatch(actionObj)修改状态
<button onClick = {()=>store.dispatch({type:'ADD',amount:1})} + </button
>
3. store.subscribe(callback) store订阅状态更新以后执行的回调函数 以遍更新视图
componentDidMount(){
<!--订阅状态改变之后做的事情-->
this.unsub = store.subscribe(()=>{
this.setState({
num:store.getState().num
}))
})
}
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import Computed from './Computed'
import store from '../store'
window.__store = store
class Counter extends Component {
constructor (props, context) {
super()
this.state = {
num: store.getState().num
}
}
componentDidMount () {
// 订阅状态变化后做的事情
this.unsub = store.subscribe(() => {
this.setState({
num: store.getState().num
})
})
}
componentWillUnmount () {
this.unsub()
}
render () {
return (<div className="container">
<button onClick={() => store.dispatch({type: 'ADD', amount: 1})}>+</button>
<span>{this.state.num}</span>
<button onClick={() => store.dispatch({type: 'MINUS', amount: 1})}>-</button>
<Computed num={this.state.num} />
</div>)
}
}
ReactDOM.render(<Counter />, document.getElementById('root'))
- 提取action的type
let ADD = 'ADD'
let MINUS = 'MINUS'
- reducer合并 reducer是单一状态数 整个应用内所有的数据都要保存到一个store中 所以若有多个组件的状态 就会有多个reducer 而createStore 只能接收一个reducer 因此需要reducer合并
- redux 中的combineReducers 是用来整合状态的方法 他接收一个对象作为参数 会把多个reducer整合到一个中
- 整合后会返回一个新的reducer 在创建store时 传入整合后的reducer
- 状态也会整合
import { createStore, combineReducers } from 'redux'
// 把 action 的 type 提取出来,作为宏
let ADD = 'ADD'
let MINUS = 'MINUS'
// 使用 redux 我们不能直接修改状态,我们需要定义修改状态的函数,这个函数称为 reducer
// 一个用来管理状态的函数
function counter(state = { num: 0 }, action) {
// state 就是当前 redux 托管的数据对象,在创建reducer时给 state 设置的默认值就是 state 的初始值
// action 是修改状态具体的动作以及修改状态需要的参数,是一个带有 type 字段的对象 { type: 'ADD', ...payload } ,而 reducer 的作用就是根据不同的 action.type 返回一个新的状态对象
switch (action.type) {
case ADD:
return {
num: state.num + action.amount
}
case MINUS:
return {
num: state.num - action.amount
}
}
// 使用 reducer 首先需要返回一个默认状态
return state
}
let todoState = {
list: [],
filter: 'all'
}
function todo(state = todoState, action) {
switch (action.type) {
case 'ADD_TODO':
return {
...state,
list: [ // 这个 list 会覆盖上面 ... 出来的 list
...state.list,
action.content
]
}
}
return state
}
// combineReducers 是用来整合状态的方法,它接收一个对象作为参数,会把多个 reducer 整合到一个中
// 整合后的 返回一个新的 reducer ,同时 状态也被整合,例如上面的 counter 和 todo 整合后的状态对象: { todo: {list: [], filter}, counter: {num: 0}}
let combinedReducer = combineReducers({
todo: todo,
counter: counter
})
let store = createStore(combinedReducer)
export default store
- 使用整合后的store 整合后的store带有命名空间 在组件中使用时需要通过对应的命名空间获取状态
- actionCreator 动作创建器 写一个函数专门生成dispatch需要的action对象 这个函数称为action-creator 这样在dispatch时 只需调用action-creator 并且传入payload即可
import * as Types from '../action-type'
function add(amount) {
return {
type: Types.ADD,
amount
}
}
function minus(amount) {
return {
type: Types.MINUS,
amount
}
}
// add 和 minus 就是 action-creator,而 1 是传递给 上面的 amount,即 payload
<button onClick={() => store.dispatch(add(1))}>+</button>
<span>{this.state.num}</span>
<button onClick={() => store.dispatch(minus(1))}>-</button>
- 文件拆分 react的模块化特性很强 对应着redux的使用也需要差分成模块化达到代码解耦的目的
- index.js 负责组合combineReducers 和导出store
- action 存放的actionCreate
- action-type 定义组件的action需要的type
- reducer 存放reducer
/store/index.js
import {createStore, combineReducers} from 'redux'
import { counter } from './reducer/counter'
import { todo } from './reducer/todo'
let combinedReducer = combineReducers({
todo: todo,
counter: counter
})
let store = createStore(combinedReducer)
export default store
store/action/counter.js
import * as Types from '../action-type'
function add(amount) {
return {
type: Types.ADD,
amount
}
}
function minus(amount) {
return {
type: Types.MINUS,
amount
}
}
export { add, minus }
----------------------------------------------------------------
store/action/todo.js
import * as Types from '../action-type'
function addTodo(content) {
return {
type: Types.ADD_TODO,
content
}
}
export { addTodo }
-------------------------------------------------
/store/action-types/index.js
export const ADD = 'ADD'
export const MINUS = 'MINUS'
export const ADD_TODO = 'ADD_TODO'
---------------------------------------------------
/store/reducer/counter
import * as Types from '../action-type'
export function counter(state = {num: 0}, action) {
switch (action.type) {
case Types.ADD:
return {
num: state.num + action.amount
}
case Types.MINUS:
return {
num: state.num - action.amount
}
}
// 使用 reducer 首先需要返回一个默认状态
return state
}
---------------------------------------------
/store/reducer/todo.js
import * as Types from '../action-type'
let todoState = {
list: [],
filter: 'all'
}
export function todo(state = todoState, action) {
switch (action.type) {
case Types.ADD_TODO:
return {
...state,
list: [ // 这个 list 会覆盖上面 ... 出来的 list
...state.list,
action.content
]
}
}
return state
}