什么情况下用Redux

明确一点,Redux是一个有用的框架,但不是非用不可。事实上,大多数情况下,你可以不用他,只用React就够了。

  • 用户的使用方式非常简单
  • 用户之间没有协作
  • 不需要与服务器大量交互,也没有使用 WebSocket
  • 视图层(View)只从单一来源获取数据

上面这些情况,都不需要使用Redux

  • 用户的使用方式复杂
  • 不同身份的用户有不同的使用方式(比如普通用户和管理员)
  • 多个用户之间可以协作
  • 与服务器大量交互,或者使用了WebSocket
  • View要从多个来源获取数据

上面这些情况才是Redux的适用场景:多交互,多数据源
从组件的角度看,如果你的应用有以下场景,可以考虑使用Redux

  • 某个组件的状态,需要共享
  • 某个状态需要在任何地方都可以拿到
  • 一个组件需要改变全局状态
  • 一个组件需要改变另一个组件的状态

总之,不要把Redux当做万灵丹,如果你的应用没那么复杂就没必要用它。

Redux的三个基本原则

单一数据源

整个应用的state被储存在一棵object tree,并且这个object tree只存在于唯一的store中

State是只读的

唯一改变state的方法就是触发action,action是一个用于描述已经发生事件的普遍对象。

使用纯函数来执行修改

为了描述action如何改变state tree,你需要并编写reducers

基本概念和API

Store

store就是保存数据的地方,你可以把它看成容器,整个应用只能有一个Store。


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

Redux提供createStore这个函数,用来生成Store

State

Store对象包含所有数据。如果想得到某个时点的数据,就要对Store生成快照。        这种时点的数据的集合,就叫做State。当前时刻的State,可以通过                            store.getState()拿到。


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

const state = store.getState();

Redux规定,一个State对应一个View。只要State相同,view就相同。

Action

State的变化会导致View的变化,但是,用户接触不到State,只能接触到View。        所以,State的变化必须是View导致的。Action就是View发出的通知,表示State应        该要变化了。

const action = {
  type: 'ADD_TODO',
  payload: 'Learn Redux'
};

Action是一个对象。其中的type属性是必须的,表示Action的名称。其他属性可        以自由设置。
Action描述当前发生的事情。改变State的唯一办法,就是使用Action。它会运送       数据到Store。

Action Creator

View 要发送多少种消息,就会有多少种 Action。如果都手写,会很麻烦。可以定义一个函数来生成 Action,这个函数就叫 Action Creator。

const ADD_TODO = '添加 TODO';

function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

const action = addTodo('Learn Redux');

上述代码中,addTodo函数就是一个Action Creator

store.dispatch()

      store.dispatch()是View发出Action的唯一方法


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

store.dispatch({
  type: 'ADD_TODO',
  payload: 'Learn Redux'
});

      store.dispatch()接受一个Action对象作为参数,将他发送出去

Reducer

store收到Action以后,必须给出一个State,这样View才会发生变化。这种State的计算过程就叫做Reducer。
Reducer是一个函数,他接受Action和当前State作为参数,返回一个新的State

const reducer=function (state,Action){
    //....
  return new_state;
}

整个应用的初始状态,可以作为State的默认值。

const defaultState=0;
const reducer=(state=defaultState,action)=>{
    switch (action.type){
    case "ADD":
      return state + action.payload;
     
    default:
      return state;
  }
}
const state=reducer(1,{
    type:"ADD",
  payload:2
});

上面代码中,reducer函数收到名为ADD的Action以后,就返回一个新的State,作为加法的计算结果。
实际应用中,Reducer函数是不用像上面这样手动调用的,store.dispath方法会触发Reducer的自动执行。为此Store需要知道Reducer函数,做法就是在生成Store的时Reducer传入createrStore方法。

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

上面代码中,createStore接受Reducer作为参数,生成一个新的Store。以后每当store.dispath发过来一个新的Action,就会自定调用Reducer,得到新的State。
Reducer还可以作为数组的reduce方法(reduce方法是使数组累加)的参数。

const actions = [
  { type: 'ADD', payload: 0 },
  { type: 'ADD', payload: 1 },
  { type: 'ADD', payload: 2 }
];

const total = actions.reduce(reducer, 0); // 3

上面代码中,数组action表示一次有三个Action,分别是0,加1和加2。数组的reudce方法接受Reducer函数作为参数,就可以得到最终的状态。

纯函数

Reducer函数最重要的特征是,他是一个纯函数,也就是说,只要是同样的输入,必得到同样的输出。
纯函数是函数是编程的概念,必须遵守以下一些约束

  - 不得改写参数
  - 不能调用系统 I/O 的API
  - 不能调用`Date.now()`或者`Math.random()`等不纯的方法,因为每次会得到不一样的结果

由于Reducer是纯函数,就可以保证同样的State,必定得到同样的View。但也正是因为这一点,Reducer函数里面不能改变State,必须返回一个全新的对象

//State是一个对象
function reducer(state, action) {
  return Object.assign({}, state, { thingToChange });
  // 或者
  return { ...state, ...newState };
}

// State 是一个数组
function reducer(state, action) {
  return [...state, newItem];
}

最好把State对象设成只读。你没法改变它,要得到新的State,唯一办法就是生成一个新对象。这样的好处是,任何时候,与某个View对应的State总是一个不变的对象。

store.subscribe()

Store允许store.subscribe方法设置监听函数,一旦State发生变化,就自动执着
这个函数。

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

store.subscribe(lister);

显然,只要把View的更新函数(对于React项目,就是组件的render方法或setState方法)放入listen,就会实现View的自动渲染。
store.subscrible方法返回一个函数,调用这个函数就可以解除监控。

let unsubscrible=store.subscrible(()=>
    console.log(store.getState());    
);

Store的实现

Store提供了三个方法

  - store.getState()//获得当前State
  - store.dispatch()//从view发出Action的唯一方法
  - store.subsrcible()//一旦State发生变化,就调用()里的函数

下面是createStore方法的一个简单实现,可以了解一下Store是怎么生成的。

const createStore=(reducer)=>{
    let state
  let listeners=[]
  
  const getState=()=>state
  
  const dispatch=(action)=>{
      state=reducer(state,action)
    listeners.forEach(listener=>listener())
  }
  
  const subscribe=(listener)=>{
      listrners.push(listener)
    return()=>{
        listeners=listeners.filter(l=>l !==listener)
    }
  }
  
  dispatch({})
  
  return {getState,dispatch,subscribe} 
}

上面代码很生动的写明白了,store的三个方法的生成过程,以及为啥调用dispatch的时候会自动调用reducer函数。

工作流程

bg2016091802.jpg

首先,用户发出Action

store.dispatch(action)        

然后Store会自动调用Reducer,并且传入两个参数,当前State和收到的Action。Reducer会返回一个新的State

let nextState=todoApp(State,action)

State一旦有变化,Store就会调用监听函数。

store.subscribe(listener)

listener可以通过store.getState()得到当前状态。如果使用的是React,这时可以出发重新渲染View。

function listener(){
    let newState=store.getState()
  component.setState({
      newState
  })
}    
Last modification:April 7th, 2021 at 07:39 pm
如果觉得我的文章对你有用,请随意赞赏