redux快速学习指南

Flux

  Redux是Flux思想的另一种实现方式。Flux是和React同时面世的。React用来替代jQuery,Flux用来替换Backbone.js等MVC框架。在MVC的世界里,React相当于V(view)的部分,只涉及页面的渲染。一旦涉及应用的数据管理部分,还是交给Model和Controller。不过,Flux并不是一个MVC框架,它用一种新的思路来管理数据。

【MVC】
  MVC是业界广泛接受的一种前端应用框架类型,这种框架把应用分为三个部分:
  Model(模型) 负责管理数据,大部分业务逻辑应该放在Model中。
  View(视图) 负责渲染用户页面,应该避免在View中涉及业务逻辑。
  Controller(控制器) 负责接受用户输入,根据用户输入调用相应的Model部分逻辑,把产生的数据结果交给View部分,让View渲染出必要的输出。
  MVC框架提出的数据流很理想,用户请求先到达Controller,由Controller调用Model获得数据,然后把数据交给View。但是,在实际框架实现中,总是允许View和Model直接通信。

【Flux】
  Facebook用Flux框架来替代原有的MVC框架,这种框架包含四个部分:
  Dispatcher 负责动作分发,维持Store之间的依赖关系
  Store 负责存储数据和处理数据相关逻辑
  Action 驱动Dispatcher的javascript对象
  View 视图负责显示用户界面

如果非要把Flux和MVC做一个对比。那么,Flux的Dispatcher相当于MVC的Controller,Flux的store相当于MVC的model,Flux的View对应于MVC的ViewAction对应给MVC框架的用户请求。

【优势】
  在Flux中,Store只有get方法,没有set方法,根本不可能直接去修改其内部状态,View只能通过get方法获取Store的状态,无法直接去修改状态,如果View想要修改Store的状态,只能派发一个action对象给Dispatcher。

【不足】
  1、Store之间依赖关系
  在Flux的体系中,如果两个Store之间有逻辑依赖关系,就必须用上Dispatcher的waitFor函数。
  2、难以进行服务器端渲染
  3、Store混杂了逻辑和状态

Redux

  Redux的含义是Reducer+Flux。Reducer是一个计算机科学中的通用概念。以Javascript为例,数组类型有reduce函数,接受的参数是一个reducer,reducer做的事情就是把数组所有元素依次做规约,对每个元素都调用一次参数reducer,通过reducer函数完成规约所有元素的功能。

Flux的基本原则是单向数据流,Redux在此基础上强调三个基本原则:
1、唯一数据源
2、保持状态只读
3、数据改变只通过纯函数完成

redux专注于状态管理,如果你的应用有以下场景,可以考虑使用 Redux。

  • 某个组件的状态,需要共享
  • 某个状态需要在任何地方都可以拿到
  • 一个组件需要改变全局状态
  • 一个组件需要改变另一个组件的状态
redux快速学习指南_第1张图片

核心概念包括:storestateactionreducer

【store】
  store是保存数据的地方,redux提供createStore函数来生成 Store。函数参数是后面要介绍的reducer。整个应用的state被储存在一棵object tree中,并且这个object tree只存在于唯一一个store中。

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

【state】
  statestore的某个时刻的快照,可以通过store.getState()取得当前时刻的statestate是只读的,唯一改变state的方法就是触发action。

const state = store.getState()

【action】
  action用来改变stateaction是一个对象,其中的type属性是必须的,其他的属性一般用来设置改变state需要的数据。state的变化会导致view的变化,但是用户接触不到state,只能接触到view。所以,state的变化必须是view导致的。action就是view发出的通知,表示state应该要发生变化了。

const action = {
  type: 'ADD_ONE',
  num: 1
}

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

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

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

const action = {
  type: 'ADD_ONE',
  num: 1
}
store.dispatch(action)

【reducer】
  reducer 是一个函数,它接受action和当前state作为参数,返回一个新的state

const reducer = (state = 10, action) => {
  switch (action.type) {
    case 'ADD_ONE':
      return state + action.num;
    default: 
      return state;
  }
};

store.dispatch发送过来一个新的actionstore就会自动调用reducer,得到新的state。

【combineReducers】
  传入store时只能传入一个reducer,多个reducer需要进行合并。

let reducers = combineReducers ({
     counter : counter,
     todo : todo
})

combineReducers实现源码

export default function combineReducers(reducers) {
    return function (state={},action) {
        return Object.keys(reducers).reduce((newState,key) => {
            newState[key]=reducers[key](state[key],action);
            return newState;
        },{});
    }
}

【简单实例】
  多余的概念不再介绍,下面用上面介绍的这四个核心概念实现一个简单的实例。

//第一步,创建action
const addOne = {
  type: 'ADD',
  num: 1
}
const addTwo = {
  type: 'ADD',
  num: 2
}
const square = {
  type: 'SQUARE'
}

//第二步,创建reducer
let math = (state = 10, action) => {
  switch (action.type) {
    case ADD:
      return state + action.num
    case SQUARE:
      return state * state
    default:
      return state
  }
}
//第三步,创建store
import { createStore } from 'redux'
const store = createStore(math)

//第四步,测试,通过dispatch发出action,并通过getState()取得当前state值
console.log(store.getState()) //默认值为10

store.dispatch(addOne) //发起'+1'的action
console.log(store.getState()) //当前值为10+1=11

store.dispatch(square) //发起'乘方'的action
console.log(store.getState()) //当前值为11*11=121

store.dispatch(addTwo) //发起'+2'的action
console.log(store.getState()) //当前值为121+2=123

【redux目录】
  1、一般地,将action.type设置为常量,这样在书写错误时,会得到报错提示。

// action/ActionTypes.js
export const ADD = 'ADD'
export const SQUARE = 'SQUARE'

  2、可以将addOne对象和addTwo对象整合成add函数的形式

// action/math.js
import { ADD, SQUARE } from '../constants/ActionTypes'
export const add = num => ({ type: ADD, num })
export const square = { type: SQUARE }

  3、根据action.type的分类来拆分reducer,最终通过combineReducers方法将拆分的reducer合并起来。上例中的action类型都是数字运算,无需拆分,只需进行如下变化

// reducer/math.js
import { ADD, SQUARE } from '../constants/ActionTypes'
const math = (state = 10, action) => {
  switch (action.type) {
    case ADD:
      return state + action.num
    case SQUARE:
      return state * state
    default:
      return state
  }
}
export default math
// reducer/index.js
import { combineReducers } from 'redux'
import math from './math'
const rootReducer = combineReducers({
  math
})
export default rootReducer

  4、将store存储到store/index.js文件中

// store/index.js
import { createStore } from 'redux'
import rootReducer from '../reducer'
export default createStore(rootReducer)

  5、最终,根路径下的index.js内容如下所示

import store from './store'
import {add, square} from './action/math'

console.log(store.getState()) //默认值为10

store.dispatch(add(1)) //发起'+1'的action
console.log(store.getState()) //当前值为10+1=11

store.dispatch(square) //发起'乘方'的action
console.log(store.getState()) //当前值为11*11=121

store.dispatch(add(2)) //发起'+2'的action
console.log(store.getState()) //当前值为121+2=123

最终目录路径如下所示


redux快速学习指南_第2张图片

UI层

前面的示例中,只是redux的状态改变,下面利用UI层来建立viewstate的联系,将根目录下的index.js的内容更改如下。

import store from './store'
import React from 'react'
import ReactDOM from 'react-dom'
import { add, square } from './action/math'

ReactDOM.render(
  

{store.getState().math}

store.dispatch(add(1))} value="+1" /> store.dispatch(add(2))} value="+2" /> store.dispatch(square)} value="乘方" />
, document.getElementById('root') )

虽然可以显示数字,但是点击按钮时,却不能重新渲染页面。

【store.subscribe()】
  接下来介绍store.subscribe()方法了,该方法用来设置监听函数,一旦state发生变化,就自动执行这个函数。该方法的返回值是一个函数,调用store.unsubscribe()这个函数可以解除监听。

import store from './store'
import React from 'react'
import ReactDOM from 'react-dom'
import { add, square } from './action/math'

const render = () => ReactDOM.render(
  

{store.getState().math}

store.dispatch(add(1))} value="+1" /> store.dispatch(add(2))} value="+2" /> store.dispatch(square)} value="乘方" />
, document.getElementById('root') ) render() store.subscribe(render)

你可能感兴趣的:(redux快速学习指南)