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
使用 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
let store = createStore(reducer);
store.subscribe(()=>
console.log(store.getState())
);
改变内部 state 唯一的方法是 dispatch 一个 action,
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 决定.
查看更多关于redux 管理你的 react 应用的详细内容...