目录

redux 是什么?

redux 和 react 的关系

为什么Rect要用 Redux

react 多组件共享 - 案例

使用redux来解决的思路

Redux 三个核心概念

理解三个核心概念

action

reducer

store

Redux功能演示核心代码  

store 相关API

Redux 代码执行过程

解决问题-redux在react中使用


redux 是什么?

Redux 是 JavaScript 应用的状态容器,提供可预测的状态管理。

当遇到如下问题时,建议开始使用 Redux:

  • 你有很多数据随时间而变化

  • 你希望状态有一个唯一确定的来源

  • 你发现将所有状态放在顶层组件中管理已不可维护

redux 和 react 的关系

Redux并不只为react应用提供状态管理, 它还支持其它的框架。

为什么Rect要用 Redux

React 是 DOM 的一个抽象层(UI 库),并不是 Web 应用的完整解决方案。因此react在涉及到数据的处理以及组件之间的通信时会比较复杂。

对于大型的复杂应用来说,这两方面恰恰是最关键的。因此,只用 React,写大型应用比较吃力。

  • 2014 年 Facebook 提出了 Flux 架构的概念,引发了很多的实现。

  • 2015 年,Redux 出现,将 Flux 与函数式编程(reducer)结合一起,很短时间内就成为了最热门的前端架构。

  • Flux 是最早的状态管理 工具,它提供了状态管理的思想,也提供对应的实现

  • 除了 Flux、Redux 之外,还有:Mobx 等状态管理工具

  • 主要的区别:组件之间的通讯问题

  • 不使用 Redux (图左边) :

    • 只能使用父子组件通讯、状态提升等 React 自带机制

    • 处理远房亲戚(非父子)关系的组件通讯时乏力

    • 组件之间的数据流混乱,出现 Bug 时难定位

  • 使用 Redux (图右边):

    • 集中式存储和管理应用的状态

    • 处理组件通讯问题时,无视组件之间的层级关系

    • 简化大型复杂应用中组件之间的通讯问题

    • 数据流清晰,易于定位 Bug

react 多组件共享 - 案例

问题描述

多组件(跨层级的)共享数据

目录结构

├── src
   ├── store          # redux目录,一般约定叫store
   │   ├── index.js   # 定义并导出store. 其中会导入reducer
   │   └── reducer    # reducer函数
   ├── App.js         # 根组件,引入Father 和 Uncle组件
   ├── Father.js      # Father组件。其中引入了Son组件
   ├── index.js       # 项目的入口文件,会导入并渲染App.js
   ├── Son.js         # Son组件
   └── Uncle.js       # Unclde组件

使用redux来解决的思路

  1. redux可以无视组件层级

  2. 对于组件系统来说,redux就是一个第三方的,全局的变量

Redux 三个核心概念

图示

理解三个核心概念

核心概念:storeactionreducer

action

  • 动作。

  • 一个js对象,包含两个属性:

    • type: 标识属性,值是字符串。多个type用action分开

    • payload:数据属性,可选。表示本次动作携带的数据

  • actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。

  • 特点:

    • 只描述做什么

    • JS 对象,必须带有 type 属性,用于区分动作的类型

    • 根据功能的不同,可以携带额外的数据,配合该数据来完成相应功能

示例:  


{ type: 'increment' } 
{ type: 'decrement', count: 2 } 
{ type: 'addTodo', name: '吃饭' }
{ type: 'removeTodo', id: 3 }

{ type: 'addN', payload: n }
{ type: 'addN', payload: {count:2} }
{ type: 'addN', payload: {name:'吃饭',age:18} }

reducer

  • 一个函数

  • 作用

      1. 初始化状态

      2. 修改状态

  • 修改状态

    根据传入的旧状态和action,返回新状态

    公式:(previousState, action) => newState

示例  

const reducer = (state = 0, action) => {
  switch (action.type) {
    case 'add':
      // 返回新的state
      return state + 1
    case 'addN':
      // 返回新的state
      return state + action.payload
    default:
      return state
  }
}

store

  • store:仓库,Redux 的核心,整合 action 和 reducer

  • 特点:

    • 一个应用只有一个 store

    • 维护应用的状态,获取状态:store.getState()

    • 创建 store 时接收 reducer 作为参数const store = createStore(reducer)

    • 发起状态更新时,需要分发 action:store.dispatch(action)

  • 其他 API, — 订阅(监听)状态变化:const unSubscribe = store.subscribe(() => {}) — 取消订阅状态变化: unSubscribe()

Redux功能演示核心代码  

定义reuder

initState = 0
function reducer(state = initState, action) {
  return state
}

定义action

const action1 = { type:'addN', payload: 12 }
// store.dispatch(action1)

const action2 = { type:'add', payload: 1 }

定义store

import { createStore } from 'redux'
// 创建 store
const store = createStore(reducer)

store 相关API

  1. store获取状态 store.getState()

  2. store修改数据,通过派发action。store.dispatch({type:xxx, payload: xx}})

  3. store添加订阅者。

//  格式:
//  取消订阅 = store.subscribe(订阅者)

//  订阅者:就是一个函数,当state值变化时,store会执行它
//  store.subscript()的返回值也是一个函数,执行它时,它的
const unSubscribe = store.subscribe(() => {
  // 状态改变时,执行相应操作
})

// 取消监听状态变化

    4. 取消订阅者。unSubscribe()

核心代码 

import { createStore } from 'redux'

initState = 0
function reducer(state = initState, action) {
  return state
}
// 创建 store
const store = createStore(reducer)

// store获取状态
console.log(store.getState())

// 更新状态
//     1. dispatch 派遣,派出。表示:分发一个 action,也就是发起状态更新
//     2. store.dispatch会 调用reducer函数,并将action传递给reducer
const action1 = { type:'addN', payload: 12 }
store.dispatch(action1)

const action2 = { type:'add', payload: 1 }
store.dispatch(action2)

// store 添加订阅者
//  store.subscribe
//  订阅者:就是一个函数,当state值变化时,store会执行它
const unSubscribe = store.subscribe(() => {
  // 状态改变时,执行相应操作
  console.log('数据变化了....')
})

// 取消监听状态变化
unSubscribe()

Redux 代码执行过程

获取默认值

只要创建 store,那么,Redux 就会调用一次 reducer, 且type是一个随机值。如下是一个示例:

这一次调用 reducer 的目的:获取状态的默认值。这个初始值将成为下一次调用 store.getState() 方法来获取 Redux 状态值的preState

  • type是随机值确保了它不会被用户业务逻辑处理,而只能去匹配默认值。

更新状态

  1. 当你需要更新状态时,就先分发动作 store.dispatch(action)

  2. Redux 内部,store 就会调用 reducer,传入:上一次的状态(当前示例中就是:0)和 action({ type: 'add' }),计算出新的状态,并返回

  3. reducer 执行完毕后,将最新的状态交给 store,store 用最新的状态替换旧状态,状态更新完毕

import { createStore } from 'redux'
const store = createStore(reducer)

function reducer(state = 0, action) {
  console.log('reducer:', state, action)
  switch (action.type) {
    case 'add':
      return state + 1
    default:
      return state
  }
}

console.log('状态值为:', store.getState()) // 10

// 发起更新状态:
// 参数: action 对象
store.dispatch({ type: 'increment' })
// 相当于: reducer(10, { type: 'increment' })

console.log('更新后:', store.getState()) // 11

解决问题-redux在react中使用

├── src
   ├── store          # redux目录,一般约定叫store
   │   ├── index.js   # 定义并导出store. 其中会导入reducer
   │   └── reducer    # reducer函数
   ├── App.js         # 根组件,引入Father 和 Uncle组件
   ├── Father.js      # Father组件。其中引入了Son组件
   ├── index.js       # 项目的入口文件,会导入并渲染App.js
   ├── Son.js         # Son组件
   └── Uncle.js       # Unclde组件

store/index.js

用reducer来初始化store

import { createStore } from 'redux'
import reducer from './reducer'
export default createStore(reducer)

reducer.js

设置初始值,并提供修改数据的逻辑

const initState = 0
export default function reducer (state = initState, action) {
  console.log(action)
  switch (action.type) {
    case 'addN':
      return state + action.payload
    case 'sub':
      return state - 1
    default:
      return state
  }
}

src/index.js

import React from 'react'
import ReactDom from 'react-dom'
import App from './App'

import store from './store/index.js'
ReactDom.render(<App />, document.getElementById('root'))

// 数据变化时,重新渲染
store.subscribe(() => {
  ReactDom.render(<App />, document.getElementById('root'))
})

src/App.js

import React from 'react'
import Father from './Father'
import Uncle from './Uncle'
export default function App () {
  return (
    <div style={{ border: '1px solid #ccc', margin: 10, padding: 10 }}>
      根组件
      <Father />
      <Uncle />
    </div>
  )
}

son.js

获取数据: store.getState()

修改数据: store.dispatch(action)

import React, { useState } from 'react'
import store from './store/index'
export default function Son () {
  const [n, setN] = useState(12)
  const add = () => {
    store.dispatch({ type: 'addN', payload: n })
  }
  return (
    <div style={{ border: '1px solid #ccc', margin: 10, padding: 10 }}>
      子组件
      {store.getState()}
      <button onClick={add}>+n</button>
      <input value={n} onChange={(e) => setN(e.target.value)} />
    </div>
  )
}

uncle.js

修改数据: store.dispatch(action)

import React from 'react'
import store from './store/index'
export default function Uncle () {
  return (
    <div style={{ border: '1px solid #ccc', margin: 10, padding: 10 }}>
      Uncle组件
      <button
        onClick={() => {
          store.dispatch({ type: 'sub' })
        }}>
        -1
      </button>
    </div>
  )
}

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐