Open xiaochengzi6 opened 2 years ago
学习方法:第一种:它][https://github.com/react-guide/redux-tutorial-cn,前六章可以跟着这篇教程学习。后面看[阮一峰](https://github.com/xiaochengzi6/Blog/issues/33#)[http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html]的第一章,在去阅读官网的基础教程无痛入门。第二种就去阅读《react小书》跟着里面讲述redux写一遍简易版的redux再去读官方教程也能更快的入门、推荐第二种
原理: 应用中所有的state(数据)都以一个对象树的形式存储在一个单一的 store 中,唯一改变的 state 的办法就是触发 action,一个描述发生什么的对象,为了描述 action 如何改变 state 树,你需要编写 Reducer
reducers的参数有 action 和 state 两个
function Reducer (state, action){ ... }
注意:state 的结构形式取决于自己,唯一需要记住的是 state 变化时就需要返回全新的对象,(因为 Reducer 是一个纯函数,依赖参数但不修改参数)而让 state 改变的办法只有通过 action 才行(store.dispatch(action)
reducer在没有 state 时会返回一个默认的 state 对象(这里的对象是描述 state 的而不是指它的数据类型如果后面没有备注都是这个意思)你要提前给出默认量。在没有指定 action(描述该发生什么的对象)就不会更新 state 参考下面的代码
reducer
对象
数据类型
// 类似于 action = {type: 'COLOR' value: 'red'} function Reducer (state, action){ if (!state){ return { "默认键值" } } //在这里我喜欢将之称为reducers规则 以下是判断,可以使用switch也可以使用if之类的。 switch (action.type) { case 'TEXT': return {"在此处和state进行合并"} ... default: return state; } }
什么是store?
store
答:store 由 createStore() 函数产生的它处理 reducers 中 state 数据和规则并由此产生了一个数据的集合 store 它可以被看作是一个数据容器store还提供了三个方法用来操作数据。
function createStore(reducer){ ... return {subscribe, dispath, getState} } let store = createStore(reducers)
由createStore(reducer)创建store产生三个实例方法
createStore(reducer)
store.subscribe(()=>{ //这里可以将事件绑定到视图层,也可以手动的订阅更新 }) store.dispatch({type: 'COLOR'}) // 唯一改变内部state的方法 store.getState() //获取当前数据
单一的数据源 State是只读的 使用纯函数来修改state
单一的数据源
State是只读的
使用纯函数来修改state
Action是数据到store的唯一载体。这句话的意思就是action是唯一可以修改store中的数据的。
//发布 action store.dispatch(action) //类似于这种形式
action 本质上是 JavaScript 普通对象(后期可能会由函数生成),约定 action 内必须使用一个字符串类型的 type。action它的目的就是提供确认关系的凭证并给出要修改的数据,action.type 就是一个凭证,而如何确认凭证的就在reducer规则中。
{ type: 'ADD_TODO' ,... } //action大致模样 { type: 'ADD_TODO', text: 'value todo' }
action创建函数 [action function] 它目的返回一个action描述对象 这样更容易编写action和测试
action创建函数
function addTodo(text) { return { type: 'ADD_TODO', text: text } }
action 主要是改变数据用的所以它和dispatch()配合起来用更加方便
//一般用法 function addTodo(text) { return { type: 'ADD_TODO', text: text } } const add = addTodi('Learn Redux'); store.dispatch(add) //结合后 const addTodo = text =>dispatch( { return { type: 'ADD_TODO', text: text } }) //注意这个dispatch不能直接使用这里是一个虚构的 dispatch指向的是store.dispatch() 但我们不能直接调用dispatch。继续往下阅读
Reducer 指定了应用状态的变化如何响应 action 并发送到 store 的,Reducer 描述了应用如何更新 state
Reducer是纯函数为了保持它的纯度不应该:
修改传入的参数 执行有副作用的操作 调用非纯函数
修改传入的参数
执行有副作用的操作
调用非纯函数
在 Reducer 首次执行时。state 为 undefined,此时应该设置并返回初始 state
const states ={ value: 'value' } function Reducer(state, action){ if(!state)return states; ... }
//state { visibilityFilter: 'SHOW_ALL', todos: [ { text: 'Consider using Redux', completed: true, }, { text: 'Keep all state in a single tree', completed: false } ] } const VisibilityFilter = { visibilityFilter: 'SHOW_ALL', todo: [] } //action 1 { type: ADD_TODO, text: 'Build my first Redux app' } //action 2 { type: TOGGLE_TODO, index: 5 } //action 3 { type: SET_VISIBILITY_FILTER, filter: SHOW_COMPLETED } //reducer const Reducer = (state = VisibilityFilter, action) =>{ switch (action.type) { // action-3 case SET_VISIBILITY_FILTER: return Object.assign({}, state, { visibilityFilter: action.filter }) // action-1 case ADD_TODO: return Object.assign({}, state, { todos: [ ...state.todos, { text: action.text, completed: false } ] }) // action-2 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 }) }) }
拆分后
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, { completed: !todo.completed }) } return todo }) default: return state } } function visibilityFilter(state = SHOW_ALL, action) { switch (action.type) { case SET_VISIBILITY_FILTER: return action.filter default: return state } }
进过拆分后最终可以整合成一个大Reducer
function todoApp(state = {}, action) { return { visibilityFilter: visibilityFilter(state.visibilityFilter,action), todos: todos(state.todos, action) } }
最终会返回一个新的 state 每一块属性都由不同的函数去生成。一个 Reducer 可以由多个小的 Reducer 组成。
Redux提供了一个combineReducers 方法,用于将 Reducer 拆分后的代码合并成一个大的 Reducer
combineReducers
import { combineReducers } from 'redux' const Reducer = combineReducers({ visibilityFilter, todos })
这样写的前提是state属性和子Reducer同名。否则就要采取以下方式
function reducer(state = {}, action) { return { a: doSomethingWithA(state.a, action), b: processB(state.b, action), c: c(state.c, action) } } const reducer = combineReducers({ a: doSomethingWithA, b: processB, c: c })
下面是combineReducer的简单实现
combineReducer
/** * 主要功能是返回一个 运行 reducer 的函数 其中会返回新的 state * @param {*} reducerMap reducer 数组 * @returns reducer */ function combineReducers(reducerMap) { const reducerKeys = Object.keys(reducerMap) // 返回 reducer 函数 const reducer = (state = {}, action) => { const newState = {} // 主要就是运行所有的 reducer for (let i = 0; i < reducerKeys.length; i++) { const key = reducerKeys[i] const currentReducer = reducerMap[key] const preState = state[key] newState[key] = currentReducer(preState, action) } // 返回新的 state return newState } return reducer }
combindeReducers把一个由多个不同reduce函数作为value的object,合并成一个最终的reducer函数。
combindeReducers
import {createStore, combineReducers} from 'redux'; var leftReducer = (state = {}, action) => { console.log('1') return state } var rightReducer = (state = {}, action) => { console.log('2'); return state; }; var Reducer = combineReducers({ leftReducer, rightReducer }) //这里为什么会打印两次? //1 //2 //1 //2
他会接收所有的reducer函数并且还会调用。最后还会将其打包成一个大的Reducer
Redux只有唯一的store。
const store = createStore(Reducer) //创建store
createStore方法还可以接受第二个参数,表示 State 的最初状态。这通常是服务器给出的。
createStore
let store = createStore(todoApp, window.STATE_FROM_SERVER)
上面代码中,window.STATE_FROM_SERVER就是整个应用的状态初始值。注意,如果提供了这个参数,它会覆盖 Reducer 函数的默认初始值。
window.STATE_FROM_SERVER
Store功能
getState() 方法获取 state dispatch(action) 方法更新 state subscribe(listener) 注册监听器 通过 subscribe(listener) 返回的函数注销监听器
getState() 方法获取 state
dispatch(action) 方法更新 state
subscribe(listener) 注册监听器
通过 subscribe(listener) 返回的函数注销监听器
subscribe(listener)
/** * 生成 store 函数 * @param {*} state 默认初始值 * @param {*} stateChange 相当于 Reducer * @returns */ function createStore(state, stateChange) { const listeners = [] const subscribe = (listener) => listeners.push(listener) const getState = () => state const dispatch = (action) => { stateChange(state, action) listeners.forEach((listender) => listender()) } return { getState, dispatch, subscribe, } }
/** * 处理中间件的函数 * @param {...any} middlewares 接收多个中间件 * @returns 返回 {store, dispatch} */ function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { var store = createStore(reducer, preloadedState, enhancer) var dispatch = store.dispatch var chain = [] // 传递给中间件的参数 var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action), } // 中间件接收 一个 { getState , dispatch } 的对象 chain = middlewares.map((middleware) => middleware(middlewareAPI)) // 这里使用 compose 包装 store.dispatch dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch, } } } function compose(...funcs) { if (funcs.length === 0) { return (arg) => arg } if (funcs.length === 1) { return funcs[0] } const last = funcs[funcs.length - 1] const rest = funcs.slice(0, -1) // [a, b, c, d, e] ==> a(b(c(d(e())))) // last(...args) 的返回值 composed 会被 f 包裹起来 然后等于 composed 再被下一个元素包裹起来 一直这样直到结束 return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args)) } // 构建一个中间件 const thunk = ({ dispatch, getState }) => (next) => (action) => { if (typeof action === 'function') { return action(dispatch, getState) } return next(action) } // 为什么要接收一个 next ? // 因为再 applyMiddleware 中 compose(...chain)(store.dispatch) 做了这样的操作 而 dispatch 也可以被看作是 next
学习方法:第一种:它][https://github.com/react-guide/redux-tutorial-cn,前六章可以跟着这篇教程学习。后面看[阮一峰](https://github.com/xiaochengzi6/Blog/issues/33#)[http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html]的第一章,在去阅读官网的基础教程无痛入门。第二种就去阅读《react小书》跟着里面讲述redux写一遍简易版的redux再去读官方教程也能更快的入门、推荐第二种
redux核心概念
原理: 应用中所有的state(数据)都以一个对象树的形式存储在一个单一的 store 中,唯一改变的 state 的办法就是触发 action,一个描述发生什么的对象,为了描述 action 如何改变 state 树,你需要编写 Reducer
reducers的参数有 action 和 state 两个
注意:state 的结构形式取决于自己,唯一需要记住的是 state 变化时就需要返回全新的对象,(因为 Reducer 是一个纯函数,依赖参数但不修改参数)而让 state 改变的办法只有通过 action 才行(store.dispatch(action)
reducer
在没有 state 时会返回一个默认的 state 对象(这里的对象
是描述 state 的而不是指它的数据类型
如果后面没有备注都是这个意思)你要提前给出默认量。在没有指定 action(描述该发生什么的对象)就不会更新 state 参考下面的代码什么是
store
?答:store 由 createStore() 函数产生的它处理 reducers 中 state 数据和规则并由此产生了一个数据的集合 store 它可以被看作是一个数据容器store还提供了三个方法用来操作数据。
由
createStore(reducer)
创建store产生三个实例方法Redux三个原则
Action
Action是数据到store的唯一载体。这句话的意思就是action是唯一可以修改store中的数据的。
action 本质上是 JavaScript 普通对象(后期可能会由函数生成),约定 action 内必须使用一个字符串类型的 type。action它的目的就是提供确认关系的凭证并给出要修改的数据,action.type 就是一个凭证,而如何确认凭证的就在reducer规则中。
action创建函数
[action function] 它目的返回一个action描述对象 这样更容易编写action和测试action 主要是改变数据用的所以它和dispatch()配合起来用更加方便
Reducer
Reducer 指定了应用状态的变化如何响应 action 并发送到 store 的,Reducer 描述了应用如何更新 state
Reducer是纯函数为了保持它的纯度不应该:
在 Reducer 首次执行时。state 为 undefined,此时应该设置并返回初始 state
Reducer 拆分
拆分后
进过拆分后最终可以整合成一个大Reducer
最终会返回一个新的 state 每一块属性都由不同的函数去生成。一个 Reducer 可以由多个小的 Reducer 组成。
combineReducers
Redux提供了一个
combineReducers
方法,用于将 Reducer 拆分后的代码合并成一个大的 Reducer这样写的前提是state属性和子Reducer同名。否则就要采取以下方式
下面是
combineReducer
的简单实现combindeReducers
把一个由多个不同reduce函数作为value的object,合并成一个最终的reducer函数。他会接收所有的reducer函数并且还会调用。最后还会将其打包成一个大的Reducer
Store
Redux只有唯一的store。
createStore
方法还可以接受第二个参数,表示 State 的最初状态。这通常是服务器给出的。上面代码中,
window.STATE_FROM_SERVER
就是整个应用的状态初始值。注意,如果提供了这个参数,它会覆盖 Reducer 函数的默认初始值。Store功能
额外的 redux 中间件的学习