博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Redux入门学习系列教程
阅读量:4086 次
发布时间:2019-05-25

本文共 6576 字,大约阅读时间需要 21 分钟。

作者结合文档,给出入门Redux学习 Demo示例

本教程主要讲解Redux的核心 API 以及 工作流程

什么是Redux

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。可以让你构建一致化的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。不仅于此,它还提供 超爽的开发体验,比如有一个时间旅行调试器可以编辑后实时预览

安装Redux

  • npm install redux --save

多数情况下,我们还需要使用 React 绑定库和开发者工具。

  • npm install redux-devtools --save-dev

核心API

  • Action
  • Reducer
  • Store

Redux三大原则

  • 单一数据源

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

  • State 只读

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

  • 使用纯函数来执行修改

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

Action

  • Action官方解释:把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。
  • 其实Action就是一个普通的对象,其中的type属性是必须的,表示 Action 的名称。其他属性可以自由设置,参照 获取关于如何构造 action 的建议。

redux约定 Action 内使用一个字符串类型的type字段来表示将要执行的动作名称。

{    type: 'ADD_TODO'}

除了type 之外,Action还可以携带需要的数据。

{    type: 'ADD_ITEM',    text: 'Learn Redux'}

Action Creator

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

const ADD_TODO = '添加 TODO'function addTodo(text) {  return {    type: ADD_TODO,    text:text  }}const action = addTodo('Learn Redux')

上面代码中,addTodo函数就是一个 Action Creator,在 Redux 中的 Action Creator 只是简单的返回一个 action而已

在 实现中,当调用 Action Creator时,一般会触发一个 dispatch

function addTodoWithDispatch(text) {  const action = {    type: ADD_TODO,    text:text  }  dispatch(action)}

在Redux 中只需把 Action Creator的结果传给 dispatch() 方法即可发起一次 dispatch 过程。

dispatch(addTodo(text))

或者创建一个被绑定的 Action Creator 来自动触发dispatch

const bindAddTodo = (text) => dispatch(addTodo(text))

然后直接调用这个函数即可完成一次dispatch过程

bindAddTodo(text)

注意:

store 里能直接通过 store.dispatch() 调用dispatch()方法,但是多数情况下我们选择使用 提供的 connect() 帮助器来调用。 可以自动把多个 action 创建函数 绑定到 dispatch() 方法上

Reducer

  • Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫做 Reducer。

  • Reducer 就是一个普通的函数

  • 当被Redux调用的时候会给Reducer传递两个参数:State 和 Action

  • 它会根据 Action 的type属性来对旧的 State 进行操作,返回新的State

const defaultState = 10const reducer = (state = defaultState, action) => {  switch (action.type) {    case Constants.INCREASE:      return state + 1    case Constants.DECREASE:      return state - 1    default:      return state  }}const state = reducer(10, {  type: Constants.INCREASE})

上面代码中,reducer函数收到名为INCREASE的 Action 后,就返回一个新的 State,作为加法的计算结果。

实际开发中,Reducer 函数不用像上面这样手动去调用,store.dispatch方法会触发 Reducer 的自动调用,为此,Store 需要知道 Reducer 函数,做法就是在生成 Store 的时候,将 Reducer 传入到createStore函数中。

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

上面代码中,createStore接受 Reducer 作为参数,生成一个新的 Store。这样以后每当store.dispatch发送过来一个新的 Action,就会自动调用 Reducer,得到新的 State

Reducer 的拆分

真正开发项目的时候State会涉及很多功能,在一个Reducer函数中处理所有逻辑会非常混乱,所以需要拆分成多个子Reducer,每个子Reducer只处理它管理的那部分State数据。然后在由一个主rootReducers来专门管理这些子Reducer。

Redux提供了一个方法:专门来管理这些子Reducer

import {createStore, combineReducers} from 'redux'const list = (state = [], action) => {  switch (action.type) {    case ADD_ITEM:      return [createItem(action.text), ...state]    default:      return state  }}const counter = (state = defaultState, action) => {  switch (action.type) {    case Constants.INCREASE:      return state + 1    case Constants.DECREASE:      return state - 1    default:      return state  }}let rootReducers = combineReducers({list, counter})

combineReducers 生成了一个类似于Reducer的函数。为什么是类似于尼,因为它不是真正的Reducer,它只是一个调用Reducer的函数,只不过它接收的参数与真正的Reducer一模一样

combineReducers 核心源码解读

function combineReducers(reducers) {  // 过滤reducers,把非function类型的过滤掉~  var finalReducers = pick(reducers, (val) => typeof val === 'function');  var defaultState = mapValues(finalReducers, () => undefined);  return function combination(state = defaultState, action) {    // finalReducers 是 reducers    var finalState = mapValues(finalReducers, (reducer, key) => {      // state[key] 是当前Reducer所对应的State,可以理解为当前的State      var previousStateForKey = state[key];      var nextStateForKey = reducer(previousStateForKey, action);      return nextStateForKey;          });    // finalState 是 Reducer的key和stat的组合。。  }}

从上面的源码可以看出,combineReducers生成一个类似于Reducer的函数combination。

注意:

当使用combination的时候,combination会把所有子Reducer都执行一遍,子Reducer通过action.type 匹配操作,因为是执行所有子Reducer,所以如果两个子Reducer匹配的action.type是一样的,那么都会匹配成功。

Store

  • Store 就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。
  • Redux 提供createStore这个函数,用来生成 Store。
  • 再次强调一下: Redux 应用只有一个单一的 store。当需要拆分数据处理逻辑时,你应该使用 reducer 组合 而不是创建多个 store。
  • 根据已有的 reducer 来创建 store 是非常容易的。在前一个章节中,我们使用 combineReducers() 将多个 reducer 合并成为一个。现在我们将其导入,并传递给createStore函数。
import { createStore } from 'redux'import reducer from '../reducer'const store = createStore(reducer)

Store提供暴露出四个API方法

  • store.getState(): 获取应用当前State。
  • store.subscribe():添加一个变化监听器。
  • store.dispatch():分发 action。修改State。
  • store.replaceReducer():替换 store 当前用来处理 state 的 reducer。
import { createStore } from 'redux'let { subscribe, dispatch, getState, replaceReducer} = createStore(reducer)

下面是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) => {    listeners.push(listener);    return () => {      listeners = listeners.filter(l => l !== listener);    }  };  dispatch({});  return { getState, dispatch, subscribe };}

发起 Actions

现在我们已经创建好了 store ,让我们来验证一下!虽然还没有界面,我们已经可以测试数据处理逻辑了。

import { addTodo, toggleTodo, setVisibilityFilter, VisibilityFilters } from './actions'// 打印初始状态console.log(store.getState())// 每次 state 更新时,打印日志// 注意 subscribe() 返回一个函数用来注销监听器let unsubscribe = store.subscribe(() =>  console.log(store.getState()))// 发起一系列 actionstore.dispatch(addTodo('Learn about actions'))store.dispatch(addTodo('Learn about reducers'))store.dispatch(addTodo('Learn about store'))store.dispatch(toggleTodo(0))store.dispatch(toggleTodo(1))store.dispatch(setVisibilityFilter(VisibilityFilters.SHOW_COMPLETED))// 停止监听 state 更新unsubscribe()

可以看到 store 里的 state 是如何变化的:

img

可以看到,在还没有开发界面的时候,我们就可以定义程序的行为。而且这时候已经可以写 reducer 和 action 创建函数的测试。不需要模拟任何东西,因为它们都是纯函数。只需调用一下,对返回值做断言,写测试就是这么简单。

Redux 工作流

flow

  • 首先,用户发出 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);   }

参考文献

阮一峰讲解redux

Redux中文文档

Redux其他系列教程

总结

本系列教程是参照文章和进行的整合和拓展。更多更详细的Redux使用方式请参照上面的参考文献。

作者:光强_上海
链接:https://www.jianshu.com/p/faa98d8bd3fa
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

你可能感兴趣的文章
Linux下用math.h头文件
查看>>
Linux中用st_mode判断文件类型
查看>>
Ubuntu修改host遇到unable to resolve host
查看>>
路由选择算法
查看>>
Objective-C 基础入门(一)
查看>>
Objective-C 基础入门(三) 读写文件与回调
查看>>
C++ STL标准库与泛型编程(一)概述
查看>>
C++ STL标准库与泛型编程(四)Deque、Queue、Stack 深度探索
查看>>
C++ STL标准库 算法
查看>>
JVM内存模型_Minor GC笔记
查看>>
SpringCloud学习之PassCloud——(一)PassCloud源代码下载
查看>>
Linux下安装Python环境并部署NLP项目
查看>>
Nginx篇-springCloud配置Gateway+Nginx进行反向代理和负载均衡
查看>>
Nginx篇-Nginx配置动静分离
查看>>
缓存篇-Redis缓存失效以及解决方案
查看>>
缓存篇-使用Redis进行分布式锁应用
查看>>
缓存篇-Redisson的使用
查看>>
phpquery抓取网站内容简单介绍
查看>>
找工作准备的方向(4月22日写的)
查看>>
关于fwrite写入文件后打开查看是乱码的问题
查看>>