React-Redux-1 基本使用

288 阅读3分钟

该文为阅读笔记,建议大家去看阮一峰老师的原文,若有侵权请联系删除

为什么引入Redux?

  • Web 应用的完整解决方案涉及完整代码组件间通信,这对于大型应用至关重要。而React只是DOM的抽象层,难以满足大型应用的开发。
  • 为了解决以上问题,随后,Facebook相继在2014年和2015年分别提出FluxRedux

一些不需要使用Redux的情况

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

适合Redux使用的场景

  • 某个组件的状态,需要共享
  • 某个状态需要在任何地方都可以拿到
  • 一个组件需要改变全局状态
  • 一个组件需要改变另一个组件的状态 参考资料: 文档,视频(前30集后30集)。

Store

  • 作用:保存数据的容器

State

  • 作用:保存在Store中的状态
  • 注:一个State对应一个View

Action

State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的

  • 作用:View发出的改变State的通知
const action = {
  type: 'ADD_TODO',
  payload: 'Learn Redux'
};

其中,type为必填,表示当前发生事情的名称。其他为选填

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 才会发生变化。
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是纯函数

约束条件

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

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

要得到新的 State,唯一办法就是生成一个新对象

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

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

store.subscribe()

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

Reducer的拆分

  • 起初,由于整个应用只有一个 State 对象,包含所有数据,对于大型应用来说,这个 State 必然十分庞大,导致 Reducer 函数也十分庞大。
const chatReducer = (state = defaultState, action = {}) => {
  const { type, payload } = action;
  switch (type) {
    case ADD_CHAT:
      return Object.assign({}, state, {
        chatLog: state.chatLog.concat(payload)
      });
    case CHANGE_STATUS:
      return Object.assign({}, state, {
        statusMessage: payload
      });
    case CHANGE_USERNAME:
      return Object.assign({}, state, {
        userName: payload
      });
    default: return state;
  }
};
  • 接着把 Reducer 函数拆分。不同的函数负责处理不同属性,最终把它们合并成一个大的 Reducer 即可。
const chatReducer = (state = defaultState, action = {}) => {
  return {
    chatLog: chatLog(state.chatLog, action),
    statusMessage: statusMessage(state.statusMessage, action),
    userName: userName(state.userName, action)
  }
};
  • 最后Redux 提供了一个combineReducers方法,用于 Reducer 的拆分。
import { combineReducers } from 'redux';

const chatReducer = combineReducers({
  chatLog,
  statusMessage,
  userName
})

export default todoApp;

两种写法:

const reducer = combineReducers({
  a: doSomethingWithA,
  b: processB,
  c: c
})

// 等同于
function reducer(state = {}, action) {
  return {
    a: doSomethingWithA(state.a, action),
    b: processB(state.b, action),
    c: c(state.c, action)
  }
}

工作流程

image.png

  • 步骤 首先,用户发出 Action。
 store.dispatch(action);

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

let nextState = todoApp(previousState, action);

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

 // 设置监听函数
 store.subscribe(listener);

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


function listerner() {
  let newState = store.getState();
  component.setState(newState);   
}