- 发布于
 
redux
- Authors
 
- Name
 - 田中原
 
redux
目录
Redux
Redux可预测的JavaScript应用程序的状态容器
帮助你写的应用行为一致,在不同的环境(client, server,native),更容易测试,提供更好的开发体验。
Start—React-Redux
安装依赖
npm install --save redux react-redux
npm install --save-dev redux-devtools
要点
- 应用程序的整个状态存储在单个存储中的对象树中。(Redux状态容器中)
 - 改变状态树的唯一方法是发出一个动作
action,一个描述发生了什么的对象。 - 要指定动作
action如何操作了状态树,需要自己编写reducer 
redux
reducer一个纯函数用于(state, action) => state
描述了一个action如何将state转换为下一个state
状态的类型(形式)取决与你自己:它可以是基本类型,一个数组,一个对象,一个Immutable.js数据结构。
重要的一点是,你不应该改变状态对象(修改state),如何state改变了,将会返回一个新的对象。
三原则
单一来源
整个应用程序的状态存储在单个存储中的对象树中。
state只读改变状态的唯一方法是发出一个
action,一个描述发生了什么的对象使用纯函数进行更改
要指定如何通过操作转换状态树,可以编写纯reducer。编写
纯函数reducer
基础
Actions
Actions
Actions是将数据从应用程序发送到store的行为。他们是store的唯一信息来源。您可以使用store.dispatch()将它们发送到store。
action是纯JavaScript对象。action必须具有指示要执行的操作类型的type属性。类型通常应定义为字符串常量。一旦应用程序足够大,可以将它们移动到一个单独的模块。
每个action尽量减少数据
Action Creators
Action Creators创建actiuon的函数,返回action。更容易测试
传统fulx中,dispatch通常在action Creators函数调用时触发。
function addTodoWithDispatch(text) {
  const action = {
    type: ADD_TODO,
    text
  }
  dispatch(action)
}
在Redux中,进行分发,需要将Action Creators函数返回的结果传入dispatch()中
例如dispath(actionCreators(arg))
Reducers
Reducers
操作描述了事情发生的事实,但不指定应用程序的状态如何变化。
设计state
应用的状态全部存储在单一的对象中,那么响应UI的状态如何做到最小?
state的状态应该使用ID进行存储,区分。更方便使用。
处理 Actions
reduce接收action和先前的state和动作,并返回下一个状态。
Reduce中不能进行的操作
- 修改参数
 - 执行次要操作,例如:API调用,路由转换
 - 调用非纯函数:
Date.now()或Math.random() 
reduce应该是一个纯函数,输入相同返回应该相同
NOTE 不要修改旧的state,
拆分Reducers
function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    case ADD_TODO:
      return Object.assign({}, state, {
        todos: [
          ...state.todos,
          {
            text: action.text,
            completed: false
          }
        ]
      })
    case TOGGLE_TODO:
      return Object.assign({}, state, {
        todos: state.todos.map((todo, index) => {
          if(index === action.index) {
            return Object.assign({}, todo, {
              completed: !todo.completed
            })
          }
          return todo
        })
      })
    default:
      return state
  }
}
上面Reducer 就过于臃肿,可以拆分开让逻辑更清晰
function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case TOGGLE_TODO:
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            complate: !todo.complate
          })
        }
        return todo
      })
    default:
      return state
  }
}
function visibilityFilyer (state = SHOW_ALL, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}
function todoApp (state = initialState, action) {
  return {
    visibilityFilter: visibilityFilter(state.visibilityFilter, action),
    todos: todos(state.todos, action)
  }
}
将state切片化。reduce组合是构建Redux应用程序的基本模式。
每个reduce只管理state的一部分。
Redux提供combineReducers()方法,可以拆分Reducer
Store
Store的职责
- 管理 app state
 - 通过 
getstate()访问state - 通过 
dispath(action)更新state - 注册监听器 
subscrive(listener) - 通过subscribe(listener)返回的函数处理监听器的注销。
 
一个app只能有一个store
Date Flow 数据流
Redux应用程序中的数据生命周期都遵循以下4个步骤
动作是描述发生了什么的简单对象,可以在任何地方调用
Store调用传入的reduce根
reduce可以将多个reduce组合成一个状态树store将根reduce返回的对象作为状态存储subscribe订阅取消订阅问题??创建store:
let store = createStore(todoApp)传入reduce执行订阅:返回值为取消订阅函数,执行reduce后触发回调
let unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)
- 触发
dispatch 
store.dispatch(addTodo('Learn about actions'))
接收action
异步操作
Actions
异步最重要的两个时间点:发送异步请求和接受到响应
两个时间点都需要改变应用状态,调用reducer。通常需要三种不同的操作
- An action informing the reducers that the request began通知
reducers异步操作开始 
reducers修改状态为isFetching,UI显示微调框
- An action informing the reducers that the request finished successfully. 通知
reducers请求完成 
reducers可以通过将新数据合并到它们管理的状态并重置isFetching来处理此操作。 UI将隐藏微调框,并显示提取的数据。
- An action informing the reducers that the request failed. 通知
reducers请求失败。 
reducer可以通过重置isFetching来处理此操作。此外,一些reducer可能希望存储错误消息,以便UI可以显示它。