Redux初探

Redux是什么:Redux是一个专门用来做状态管理的JS库(不是React插件库)。它可以用在React,Angular,Vue应用中,但基本和React配合使用。用于集中式管理React应用中多个组件共享的状态。

首先我们先介绍一个概念集中式管理,集中式管理要求状态在哪里,修改状态的行为就定义在那个组件。

但是集中式管理有一个问题。一个组件下面有很多路由组件。如果这些组件的行为全部放在一个文件下会造成很大的冗余。

然而Redux使用集中式管理来管理状态。将状态以及状态管理的方法放在一处,需要的时候调用状态管理的方法。此时状态不在组件的内部,而是在Redux中。



组件的两大功能:

  • 展现数据
  • 与用户交互更新数据

Action Creators,Store,Reducers都是Redux代码。因此整个过程可以看做是React组件和Redux进行交互。

展现数据:Store是Redux中的核心对象。从图中可以看出React组件是从Store中读取状态。

更新新的状态显示:使用分发功能时会使用到action,其中有两个属性type,data。Action Creators是一个工厂函数,用于修改action对象。我们需要传递一个type和data。type代表的是事件的类型。Action Creators通过type决定生成什么类型的Action。data是相关的数据。

Reducers相当于一个函数,该函数的形参是previousState和action,返回值为newState。返回的newState交给store进行状态的更新。

React中状态无法直接更新,必须调用this.setState()

总结:一个组件重要的功能是两方面:显示状态和更新状态。显示状态可以通过Store来修改状态。更新状态时我们主要做两件事,首先是发送通知,通过dispatch。之后是实现Reducers函数产生新的状态。

什么情况下需要使用Redux

  1. 总体原则:能不用就不用,如果不用比较吃力才考虑使用。
  2. 某个组件的状态,需要共享。
  3. 某个状态需要在任何地方都可以拿到。
  4. 一个组件需要改变全局状态。
  5. 一个组件需要改变另一个组件的状态。

使用Redux

首先先下载依赖包

npm install --save redux

Store对象

作用:Redux库最核心的管理对象。
内部维护:state,reducer
核心方法:

  • getState()
  • dispatch(action)
  • subscribe(listener)

编码:

  • store.getState()
  • store.dispatch({type:'INCREMENT', number})
  • store.subscribe(render)

Redux三个核心概念

action

标识要执行行为的对象
包含两个方面的属性:

  • type:标识属性,值为字符串,唯一,必要属性。
  • xxx:数据属性,值为任意类型,可选属性。
    例子:
const action = {
  type: "INCREMENT",
  data: 2
}

Action.Creator(Action的工厂函数)的创建

const increment = (number) => ({type: "INCREMENT", data: number})

reducer

根据老的state和action产生新的state的纯函数。
例子:

export default function counter(state=0, action){
  switch(action.type){
    case: "INCREMENT":
      return state+action.data
    case: "DECREMENT":
      return state-action.data
    default:
      return state
  }
}

注意:

  1. 每一次都返回一个新的状态数据。
  2. 不要改变以前的状态数据。

store

将state, action与reducer联系到一起的对象。
如何得到该对象:

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

此对象的功能:
getStete():得到state
dispatch(action):分发action,触发reducer的调用,产生新的state。
subscribe(listener):注册监听,当产生了新的state对象时,自动调用。

Redux实例

我们需要实现以下的效果:



点击“加号”,“减号”按钮,上面的数字分别增加或减少显示的数字。点击“increment if odd”如果显示的数字为奇数则增加显示的数据。点击“increment async”隔一段时间后增加显示的数据。

首先在index.js中引入Store对象

import {createStore} from 'redux'

之后是创建Store对象

const store = createStore()

之后是编写Action Creators(reducers.js)并将其传给Store对象。和前面说的一样Action Creators相当于一个工厂方法根据传递的type决定产生什么样的Action。

export function counter(state = 0, action) {
    switch (action.type){
        case "INCREMENT":
            return state + action.data
        case "DECREMENT":
            return state - action.data
        default:
            return state
    }
}

这里做一些改进。由于我们在传递type的时候可能会将type的类型写错。所以这里我们最好写一个类(action-types.js)来统一管理这些字符。

export const INCREMENT = 'INCREMENT'
export const DECREMENT = 'DECREMENT'

之后在reducers.js中引入之前写的action-types.js

import {INCREMENT, DECREMENT} from './action-types'

export function counter(state = 0, action) {
    switch (action.type){
        case INCREMENT:
            return state + action.data
        case DECREMENT:
            return state - action.data
        default:
            return state
    }
}

这个时候我们就不需要担心type写错的问题了。

之后回到index.js中,引入之前写的reducers.js。并将Action Creators传递给Store对象。并将Store对象传递给组件类。

import {counter} from './redux/reducers'

const store = createStore(counter)

function new_render(){
    render(, document.getElementById('root'))
}

new_render()

store.subscribe(new_render)

让我们来到组件类app.jsx。由于状态是被Redux管理的。因此在组件类中我们无需定义state了。状态值的获取与更新也要经过Redux。不需要自己写方法了。例如:

//获取状态值
const count = this.props.store.getState()
//更新状态值
this.props.store.dispatch({type: INCREMENT, data: number})

整个app.jsx的代码如下:

import React, {Component} from 'react'
import {INCREMENT, DECREMENT} from '../redux/action-types'

class App extends Component{
    increment = () => {
        const number = this.select.value*1
        this.props.store.dispatch({type: INCREMENT, data: number})
    }

    decrement = () => {
        const number = this.select.value*1
        this.props.store.dispatch({type: DECREMENT, data: number})
    }

    incrementIfOdd = () => {
        const number = this.select.value*1
        const count = this.props.store.getState()
        if(count %2 === 1)
            // this.setState({count: count + number})
            this.props.store.dispatch({type: INCREMENT, data: number})
    }

    incrementAsync = () => {
        const number = this.select.value*1
        setTimeout(() => {
            this.props.store.dispatch({type: INCREMENT, data: number})
        }, 1000)
    }

    render(){
        const count = this.props.store.getState()
        return (
            

Click {count} times

         
) } } export default App

使用react-redux进行简化

react-redux是一个react插件库。专门用于简化在react应用中使用redux。

export default connect(
    state => ({count: state}),
    {increment, decrement}
)(App)

在此示例中。state和{increment, decrement}会被结构传递给App组件。状态放到了Redux中,我们需要这些状态就需要属性来接收。connect起到了传递属性的作用。注意:connect中的属性名必须和组件中的属性名一致。

React-Redux将所有的组件分为两大类:

  • UI组件
    不使用Redux的API
    一般放在components文件夹下
  • 容器组件
    使用Redux的API
    一般保存在containers文件夹下
文件结构

action-types.js:包含所有action类型的名称常量。
actions.js:包含了所有的action,工厂函数。
reducers.js:包含多个reducer函数。根据老的state和action,返回一个新的state。
store.js:redux最核心的管理对象。
components下存放着UI组件(counter.jsx)

import React, {Component} from 'react'
import PropTypes from 'prop-types'

export default class Counter extends Component{

    static propTypes = {
        count: PropTypes.number.isRequired,
        increment: PropTypes.func.isRequired,
        decrement: PropTypes.func.isRequired
    }

    increment = () => {
        const number = this.select.value*1
        this.props.increment(number)
    }

    decrement = () => {
        const number = this.select.value*1
        this.props.decrement(number)
    }

    incrementIfOdd = () => {
        const number = this.select.value*1
        const {count} = this.props
        if(count %2 === 1)
            // this.setState({count: count + number})
            this.props.increment(number)
    }

    incrementAsync = () => {
        const number = this.select.value*1
        setTimeout(() => {
            this.props.increment(number)
        }, 1000)
    }

    render(){
        const {count} = this.props
        return (
            

Click {count} times

         
) } }

containers下放容器组件(app.jsx)

import {decrement, increment} from "../redux/actions";
import {connect} from "react-redux";
import Counter from "../components/counter";

export default connect(
    state => ({count: state}),
    {increment, decrement}
)(Counter)

Provider组件:
让所有组件都可以得到state数据


  

connect组件:
用于包装UI组件形成容器组件。将组件和Redux关联起来。

import {connect} from 'react-redux'
connect(
  mapStateToProps,
  mapDispatchToProps
)(Counter)

mapStateToProps():
将外部数据(即state对象)转换为UI组件的标签属性。

const mapStateToProps = function(state){
  return (
    {value: state}
  )
}

mapDispatchToProps():
将分发action的函数转换为UI组件的标签属性。
简洁语法可以直接指定为actions对象或包含多个action方法的对象。

管理多个Reducer

import {combineReducers} from 'react'

合并多个reducer放在一起管理。

假设此时有两个reducer。我们不应将它们分别暴露。而是统一放到combineReducers方法中进行统一暴露。同时之前暴露的方法也要统一改成统一管理的方法。

你可能感兴趣的:(Redux初探)