redux 只是一个状态管理简述由于项目原因,笔者接触了一些前端框架,其中react,wepy等都可以使用redux管理状态不多说,本篇文章主要从react和wepy中说明redux的原理以及如何使用阅读前需了解(本文中仅作简单描述,详细了解请自行Google)纯函数 符合以下两点性质的函数即为纯函数函数执行不改变外部变量函数的输出结果仅依赖于输入参数高阶组件即一个函数,接收一个组件作为参数,输出一个新组件观察者模式即发布订阅模式,可以理解为给一个事件绑定多个函数,事件触发时多个绑定函数全部执行react基础react官方中文文档wepy基础(有vue基础也可以)wepy官方文档reduxreact中的context属性简单的说,context就是一个全局变量,它可以被一个高阶组件及该高阶组件的所有子组件,孙组建等等共享举个例子,下图是一个react页面react页面树形结构正常的状态提升及数据下放使用context的树形结构由上面三图可以看出,本应一层一层传递的数据,在使用context后,变得方便了。高阶组件以下的所有子组件都可以直接从context中获取数据。context并不完美这看似方便的方法,实际上引发了一个老生常谈的问题,即全局变量控制问题context 里面的数据能被随意接触就能被随意修改,每个组件都能够改 context 里面的内容会导致程序的运行不可预料同时context的出现也打破了组件和组件之间通过 props 传递数据的规范,极大地增强了组件之间的耦合性。试想,若是所有组件都可以通过xxx=‘xxx’来修改状态,我们获取并控制当前状态的难度是否变大?在大型复杂项目中,我们可能都无法确定某数据是如何变成当前值的为了避免这种情况出现,redux就出现了redux解决了问题为了解决模块(组件)之间需要共享数据和数据可能被任意修改导致不可预料的结果时间的矛盾,redux团队想出了一个办法,即把事情搞复杂一些,提高数据修改的门槛:模块(组件)之间可以共享数据,也可以改数据。但是我们约定,这个数据并不能直接改,你只能执行某些我允许的某些修改,而且你修改的必须大张旗鼓地告诉我。所以,修改数据的函数dispatch出现了function dispatch (action) { switch (action.type) { case ‘UPDATE_TITLE_TEXT’: appState.title.text = action.text break case ‘UPDATE_TITLE_COLOR’: appState.title.color = action.color break default: break }}即所有的数据都必须通过调用dispatch修改。dispatch({ type: ‘UPDATE_TITLE_TEXT’, text: ‘hello world’ }) // 修改标题文本dispatch({ type: ‘UPDATE_TITLE_COLOR’, color: ‘blue’ }) // 修改标题颜色如图所示引入redux前,各组件直接修改数据现在,必须通过dispatch修改数据抽离store并监控数据变化我们把它们集中到一个地方,给这个地方起个名字叫做 store,然后构建一个函数 createStore,用来专门生产这种 state 和 dispatch 的集合,这样别的 App 也可以用这种模式了:/@paramstate 初始状态stateChanger 一个修改state的函数/function createStore (state, stateChanger) { const getState = () => state const dispatch = (action) => stateChanger(state, action) return { getState, dispatch }}本例中页面通过renderApp等函数刷新,为了避免dispatch后页面数据不变化(render函数不执行)我们必须引入观察者模式,使dispatch后,app自动执行render函数function createStore (state, stateChanger) { const listeners = [] const subscribe = (listener) => listeners.push(listener) const getState = () => state const dispatch = (action) => { stateChanger(state, action) listeners.forEach((listener) => listener()) } return { getState, dispatch, subscribe }}function renderApp (appState) { renderTitle(appState.title) renderContent(appState.content)}function renderTitle (title) { const titleDOM = document.getElementById(’title’) titleDOM.innerHTML = title.text titleDOM.style.color = title.color}function renderContent (content) { const contentDOM = document.getElementById(‘content’) contentDOM.innerHTML = content.text contentDOM.style.color = content.color}let appState = { title: { text: ‘React.js 小书’, color: ‘red’, }, content: { text: ‘React.js 小书内容’, color: ‘blue’ }}function stateChanger (state, action) { switch (action.type) { case ‘UPDATE_TITLE_TEXT’: state.title.text = action.text break case ‘UPDATE_TITLE_COLOR’: state.title.color = action.color break default: break }}const store = createStore(appState, stateChanger)store.subscribe(() => renderApp(store.getState())) // 监听数据变化renderApp(store.getState()) // 首次渲染页面store.dispatch({ type: ‘UPDATE_TITLE_TEXT’, text: ‘《React.js 小书》’ }) // 修改标题文本store.dispatch({ type: ‘UPDATE_TITLE_COLOR’, color: ‘blue’ }) // 修改标题颜色至此,我们已经大概构建了一个redux的骨架,接下来我们将完善它严重的性能问题不知道读者有没有发现,当我们通过dispatch修改标题的文字时,整个App就会刷新一次,当我们修改文本的颜色时,整个App也会刷新一次,这样就频繁的全部刷新就造成了极大的性能问题那么,能否修改title,仅刷新title;修改content,也仅刷新content呢?我们使render函数接收2个参数(newState, oldState = {})并且在刷新前进行比较function renderApp (newAppState, oldAppState = {}) { // 防止 oldAppState 没有传入,所以加了默认参数 oldAppState = {} if (newAppState === oldAppState) return // 数据没有变化就不渲染了 console.log(‘render app…’) renderTitle(newAppState.title, oldAppState.title) renderContent(newAppState.content, oldAppState.content)}function renderTitle (newTitle, oldTitle = {}) { if (newTitle === oldTitle) return // 数据没有变化就不渲染了 console.log(‘render title…’) const titleDOM = document.getElementById(’title’) titleDOM.innerHTML = newTitle.text titleDOM.style.color = newTitle.color}function renderContent (newContent, oldContent = {}) { if (newContent === oldContent) return // 数据没有变化就不渲染了 console.log(‘render content…’) const contentDOM = document.getElementById(‘content’) contentDOM.innerHTML = newContent.text contentDOM.style.color = newContent.color}这样就可以提高性能了吧,每次只刷新需要刷新部分啦~~才怪!我们确实修改了对象内的属性值,但是newState和oldState所指的不还是一个对象吗?所以为了进行判断,我们还要修改前面的stateChanger函数function stateChanger (state, action) { switch (action.type) { case ‘UPDATE_TITLE_TEXT’: return { // 构建新的对象并且返回 …state, title: { …state.title, text: action.text } } case ‘UPDATE_TITLE_COLOR’: return { // 构建新的对象并且返回 …state, title: { …state.title, color: action.color } } default: return state // 没有修改,返回原来的对象 }}现在我们才真正提高了性能reduer为了让程序的结构更加清晰,我们把原始state放入stateChanger中,并把stateChanger改名为reducer为什么叫redcer? 别问为什么,没有理由!function reducer (state, action) { if (!state) { return { title: { text: ‘hello world’, color: ‘red’, }, content: { text: ‘hello world content’, color: ‘blue’ } } } switch (action.type) { case ‘UPDATE_TITLE_TEXT’: return { …state, title: { …state.title, text: action.text } } case ‘UPDATE_TITLE_COLOR’: return { …state, title: { …state.title, color: action.color } } default: return state }}总结现在的代码和react,wepy关系都不大,在下一篇文章中,我会讲述如何具体地在react中使用redux感谢 @胡子大哈 老师的《react小书》,本章有很多代码都是摘自该书本文参考react小书