react - redux 全局状态管理 、多组件共享状态 - 例子有详细注释


先来看一下Redux的流程图
在这里插入图片描述

基本概念
  1. Store: 保存数据的地方,可以看成一个容器,一个应用只能有一个Store
  2. Store: 对象包含所有数据。如果想要得到某个时点的数据,就要对Store生成快照。这种时点的数据集合,就叫做State
  3. Action: 是一个对象。其中的type属性是必须的,表示Action的名称(下面会有例子),其他属性可以自由设置
  4. Action Creator: View要发送多少种消息,就会有多少种Action。如果都手写会很麻烦,可以定义一个函数来生成Action,这个函数就叫 actionCreator
  5. store.dispatch(): 是View发出Action的唯一方法
  6. Reducer: 是一个纯函数。 Store收到Action以后,必须给出一个新的State,这样View才会发生变化。这种State的计算过程就叫做Reducer
  7. 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)
  }
}

效果
在这里插入图片描述

参考
阮一峰的网络日志
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值