redux 管理你的 react 应用

         Redux-(Reducer,Action,Store)

 

action: 相当于新闻摘要,是一个用于描述已发生事件的对象,把数据从应用传入 store, 是一个 JS 对象,必须包含一个 Type 字段,只有触发 action 才能修改 state, 只有 state 改变才能触发 render() 函数,只有 render 函数调用才能更新 UI.

 store:唯一的,存储应用所有 state ,创建一个 store:let store  = createStore(reducer)

store 有一个 dispatch 函数,他关注应用的业务实现逻辑,你可以用 dispatch 函数分发一个 action 到你定义的 reducer 函数, reducer 函数就是具体说明如何通过 action 改变 state , store 会分发这个 action 对象到它所拥有的所有的 reducer 函数来影响应用的状态,当然只有真正关注该 action 逻辑的 reducer 才会真正改变 state,这些都是中间件来完成的.

store.dispatch(action)分发 action reducer.

reducer:action 只是描述一个已发生事件,触发 action 才会改变 state, reducer 就是说明 action 如何改变 state ,他是一个纯函数,接受一个先前的 state 和一个 action, 并返回一个新的 state, 所有订阅 store.subscribe(listener)的监听器都将被调用, store.getState() 获取新的 state, component.setState(newState)更新 UI.

Middleware: redux 中间件被设计成可组合的,会在 dispatch 之前调用的函数,创建一个日志中间件,它会简单的输出 dispatch 前后的应用状态, redux中间件的签名:middleware::next -> action -> retVal

Snip20160901_26.png

Snip20160901_27.png

使用 redux的一个好处就是他让 state 的变化过程变得可预知和透明,每当一个 action 发起之后,新的state 就会被计算和保存下来, state 不能被自身修改,只能由特定的 action 引起变化.

 

1.应用中所有的 state都以一个对象树的形式储存在一个单一的 store 中(注意:只有一个 store,reducer 可以拆分成多个子 reducers);

2.唯一改变 state的方法是触发 action, action 是一个描述发生什么的JS对象,必须包含一个 type 字段, 调用 store.dispatch(action)触发action把数据传入 store,只有改变 state才能 触发 render() 函数才能重新渲染 UI.

3.为了描述 action 如何改变 state树,你需要编写 reducer,这是一个普通的函数,接收先前的 state 和 action, 并返回新的 state.reducer 必须是纯净的.

4.把要做的修改变成一个普通对象,这个对象叫做 Action, 而不是直接修改 state.然后编写专门的函数来决定每个 action 如何改变应用的 state, 这个函数叫做 reducer.

5.跟 flux 的区别是只有一个单一的store 和一个根级的 reducer.随着应用的变大,应该把根级的 reducer 拆分成多个小的 renducers,分别独立的操作 state 树的不同部分,而不是添加新的 store.

6.他的美在于做复杂应用和庞大系统时优秀的扩展能力,由于它可以用 action 追溯应用的每一次修改.

(state,action) => state 的函数 这是一个 reducer, 描述了 action 如何把 state 转变为下一个 state.

function counter(state = 0, action) {

  switch (action.type) {

  case 'INCREMENT':

    return state + 1;

  case 'DECREMENT':

    return state - 1;

  default:

    return state;

  }

}

创建 Redux store 来存放应用的状态

API 是 subscribe dispatch  getState

Snip20160901_24.png

let store = createStore(reducer);

store.subscribe(()=>

console.log(store.getState())

);

改变内部 state 唯一的方法是 dispatch 一个 action,

Snip20160901_25.png

action 可以被序列化,用日记记录和储存下来,后期还可以以回放的方式执行

store .dispacth({type:INCREMENT});

Action:

把数据从应用传到 store 的有效载荷,他是 store 数据的唯一来源,一般通过 store.dispatch() 将 action 传到 store.

const ADD_TODO = ‘ADD_TODO’

{

type:ADD_TODO,

text:’Build my first Redux app’

}

action 本质上是 JS 普通对象(就是键值对),action 内 必须使用一个字符串类型的 type 字段来表示将要执行的动作,多数情况下, type 会被定义成字符串常量,当应用的规模越来越大的时候,使用单独的模块或文件来存放 action,如:

import{ADD_TODO,REMOVE_TODO}from’../actionTypes’

action 创建函数:就是生成 action的函数,在redux 中的 action 创建函数只是简单的返回一个 action: function addTodo (text){

return{

type:ADD_TODO,

text

}

}

redux 中只需把 action 创建函数的结果传给 dispatch ()方法即可发起一次 dispatch 的过程

dispatch(addTodo(text))

或者创建一个被绑定的 action 创建函数来自动 dispatch:

const boundAddTodo = (text) => dispatch (addTodo(text)) 然后直接调用 boundAddTodo(text);

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

Reducer:

action 只是描述了有事情发生这个事实,并没有指明应用如何更新 state, 而这正是 reducer 要做的时,

reducer 必须要保持纯净,永远不要在 reducer 里做这些操作:

修改传入参数;

执行有副作用的操作,如 API 请求和路由跳转;

调用非纯函数,如 Date.now() 或 Math.random()

我们将以指定的 state 的初始状态作为开始, redux 首次执行时, state 为 undefined, 此时我们可借机设置并返回应用的初始 state.

import {VisibilityFilters}from ‘./actions’

const initialState = {

visibilityFilter:VisibilityFilters.SHOW_ALL,

todos:[]

};

function todoApp (state,action){

if (typeof state === ‘undefined’ ){

return initialState

}

return state

}

function todoApp(state = initialState, action) {

  switch (action.type) {

    case SET_VISIBILITY_FILTER:

      return Object.assign({}, state, {

        visibilityFilter: action.filter

      })

    default:

      return state

  }

}

Redux -Store

store 有以下的职责:

维持应用的 state;

提供 getState()方法获取 state;

提供 dispatch(action)方法更新 state;

通过 subscribe(listener)注册监听器;

通过 subscribe(listener)返回的函数注销监听器;

redux应用只有一个单一的 store

根据已有的 reducer 创建store

import { createStore}from ‘redux’

import todoApp from ‘./reducers’

let store  = createStore(todoApp)

 

import { addTodo, toggleTodo, setVisibilityFilter, VisibilityFilters } from './actions'

 

// 打印初始状态

console.log(store.getState())

 

// 每次 state 更新时,打印日志

// 注意 subscribe() 返回一个函数用来注销监听器

let unsubscribe = store.subscribe(() =>

  console.log(store.getState())

)

 

// 发起一系列 action

store.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();

数据流

redux 中的数据的生命周期遵循4个步骤

1.调用 store.dispatch(action )

2.store 中调用传入的 reducer 函数

注意: reducer 是一个纯函数,他仅仅用于计算下一个 state, 他应该是完全可以预测的,多次传入相同的输入必须产生相同的输出,他不应做有副作用的操作,如 API 调用或路由跳转,这些应该在 dispatch action 前发生

3.根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树

4.store 保存了根 reducer 返回的完整的 state 树,这个新的树就是应用的下一个 state, 所有订阅 store.subscribe(listener)的监听器都将被调用;监听器里可以调用 store.getState() 获得当前 state, 现在可以用新的 state 来更新 UI, 如果使用了 react redux 这类的绑定库,这时就可以调用 component.setState(newState)来更新.

API文档

createStore(reducer,[initialState])

创建一个一个 store 存放应用中所有的 state

参数: 

1.reducer(Function):接受两个参数,分别是当前的 state 和要处理的 action, 返回一个新的state 树.

2.[initialState](any):初始时的 state

返回值:

store 中保存所有的 state 对象,改变 state 唯一的方法是 store.dispatch(action).也可以用 subscribe 监听 state 的变化,然后更新 UI.

(1)如果 state 是普通对象,永远不要修改它,比如 reducer 里不要使用 object.assign(state,newData),应该使用 Object.assign({},state,newData),这样才不会覆盖旧的 state

(2)当 store 创建后, redux 会 dispatch 一个 action到 reducer 上,来用初始的 state 填充 store, 你不需要处理这个 action, 但要记住,如果第一个参数也就是传入的 state 如果是 undefined 的 话, reducer 应该返回初始的 state 的值.

store 方法

getState()

dispatch(action)

subscribe(listener)

replaceReducer(nextReducer)

combineReducers(reducers)

把一个由多个不同 reducer函数作为 value 的 object, 合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore

合并后的 reducer 可以调用各个子 reducer, 并把他们的结果合并成一个 state 对象, state 的结构由传入的多个 reducer 的key 决定.

Snip20160901_20.png

Snip20160901_21.png

 

 

Snip20160901_22.png

Snip20160901_23.png

 

posted @ 2016-09-20 14:23  ChrisZhou6605  阅读(723)  评论(0编辑  收藏  举报