整个应用的state被储存在一棵object tree中,并且这个object tree只存在于唯一个store中。来自于服务器端的state也可以序列化之后直接注入客户端中
console.log(store.getState()) //输出 { visibility: 'SHOW_ALL', todos: [ { text: 'using redux', completed: true }, { text: 'keep all state in a single tree', completed: false } ] }唯一改变state的方法就是触发action,action是一个用于描述已发生事件的普通对象。 这样确保了视图和网络请求都不能直接修改state,它们只能触发一个action,至于是否修改state,由action的集中处理决定。action严格按照先后顺序执行,不用担心race condition竞态条件。action是普通对象,可以被日志打印,序列化等等,相当于可以自定义的event
store.dispatch({ //action的type属性为大写,是action的区分标识 type: 'COMPLETE_TODO', //可以附带其他key:value键值对 index: 1 }) store.dispatch({ //下文reducer中用到 type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_COMPLETED' })实际开发中,当我使用localstorage对state进行持久化存储时,不能通过直接清除localstorage来删除某一个state,而应该触发一个DELETE的action来清除state
reducer是一些纯函数,接收先前的state和action,并返回新的state,刚开始可以只有一个reducer,当应用变大的时候,可以根据业务逻辑拆分成多个reducer,分别操作state tree的不同部分,
function visibilityFilter(state='SHOW_ALL', action){ switch(action.type){ //上文的action case 'SET_VISIBILITY_FILTER': //返回状态 return action.filter default: return state } }Action是把数组从应用传到store层的载体,它是store数据的唯一来源,添加新todo任务的action是这样的:
const ADD_TODO = 'ADD_TODO' { type: ADD_TODO, text: '' }创建一个action需要action创建函数
function addTodo(text){ return { type: ADD_TODO, text: '' } }触发一次action则是发起一次dispatch过程
diapatch(addTodo(text))也可以创建一个变量动态绑定
const boundAddTodo = (text) => dispatch(addTodo(text)) //相当于boundAddTodo = function(text){ return dispatch(addTodo(text)) }所以可以直接调用
boundAddTodo(text);action 来描述“发生了什么”, reducers 根据 action 更新 state,而store就是把它们联系到一起的对象,Store有以下职责 1. 维持应用的state 2. 提供getState()方法获取当前state 3. 提供dispatch(action)方法更新state 4. 通过subscribe(listener)注册监听器 5. 通过subscribe(listener)返回的函数注销监听器 redux应用只有单一的store, 当需要拆分数据处理逻辑时,应该使用 reducer 组合而不是创建多个 store。
redux的数据流遵循以下4个步骤 1. 调用store.dispatch(action),可以在任何地方调用 store.dispatch(action),包括组件中、XHR 回调中、甚至定时器中。 2. Store 会把两个参数传入 reducer: 当前的 state 树和 action 3. Redux 原生提供combineReducers()辅助函数,来把根 reducer 拆分成多个函数,用于分别处理 state 树的一个分支。
function todos(state = [], action) { // 省略处理逻辑... return nextState; } function visibleTodoFilter(state = 'SHOW_ALL', action) { // 省略处理逻辑... return nextState; } //拆分后将多个函数合并 let todoApp = combineReducers({ todos, visibleTodoFilter })Redux store 保存了根 reducer 返回的完整 state 树。开发复杂的应用时,不可避免会有一些数据相互引用。尽可能地把 state 范式化,不存在嵌套。把所有数据放到一个对象里,每个数据以 ID 为主键,不同实体或列表间通过 ID 相互引用数据。把应用的 state 想像成数据库。例如,实际开发中,在 state 里同时存放 todosById: { id -> todo } 和 todos: array 是比较好的方式 另外,在return state的时候
return Object.assign({}, state, { visibilityFilter: action.filter })不要修改state, 不能使用 Object.assign(state, { visibilityFilter: action.filter }),因为它会改变第一个参数的值。
新闻热点
疑难解答