摘要:高阶组件以下的所有子组件都可以直接从中获取数据。所以,修改数据的函数出现了即所有的数据都必须通过调用修改。
redux 只是一个状态管理 简述
本篇文章主要说明redux的基本原理以及如何使用
阅读前需了解(本文中仅作简单描述,详细了解请自行Google)
纯函数
符合以下两点性质的函数即为纯函数
函数执行不改变外部变量
函数的输出结果仅依赖于输入参数
高阶组件
即一个函数,接收一个组件作为参数,输出一个新组件
观察者模式
即发布订阅模式,可以理解为给一个事件绑定多个函数,事件触发时多个绑定函数全部执行
react基础
react官方中文文档
wepy基础(有vue基础也可以)
wepy官方文档
redux react中的context属性简单的说,context就是一个全局变量,它可以被一个高阶组件及该高阶组件的所有子组件,孙组建等等共享
举个例子,下图是一个react页面react页面树形结构
正常的状态提升及数据下放
使用context的树形结构
由上面三图可以看出,本应一层一层传递的数据,在使用context后,变得方便了。
高阶组件以下的所有子组件都可以直接从context中获取数据。
这看似方便的方法,实际上引发了一个老生常谈的问题,即全局变量控制问题
context 里面的数据能被随意接触就能被随意修改,每个组件都能够改 context 里面的内容会导致程序的运行不可预料
同时context的出现也打破了组件和组件之间通过 props 传递数据的规范,极大地增强了组件之间的耦合性。
试想,若是所有组件都可以通过xxx="xxx"来修改状态,我们获取并控制当前状态的难度是否变大?
在大型复杂项目中,我们可能都无法确定某数据是如何变成当前值的
为了避免这种情况出现,redux就出现了
为了解决模块(组件)之间需要共享数据和数据可能被任意修改导致不可预料的结果时间的矛盾,
redux团队想出了一个办法,即把事情搞复杂一些,提高数据修改的门槛:模块(组件)之间可以共享数据,也可以改数据。但是我们约定,这个数据并不能直接改,你只能执行某些我允许的某些修改,而且你修改的必须大张旗鼓地告诉我。
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 也可以用这种模式了:
/** *@param *state 初始状态 *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小书
全部代码make-redux
本文如果有错,欢迎指出
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/100205.html
摘要:和的结合简述相信很多前端开发者都听说或使用过,我曾写过一篇关于快速理解的文章,虽说是快速理解,但实际上更应该叫做复习吧。它通过高阶函数,纯函数使我们在编写组件时完全不用接触相关内容,只通过将组件和数据连接起来即可。 react-redux react和redux的结合 简述 相信很多前端开发者都听说或使用过react-redux,我曾写过一篇关于快速理解redux的文章,虽说是快...
摘要:协调状态的这三个方面是前端开发的重要组成部分,对这项任务有不同程度的支持。这使得保持高度统一。的真正威力到目前为止,看上去只是的辅助工具。在的术语中这称之为派发动作。撤销重做流行的撤销重做功能需要系统级规划。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 你知道 Redux 真正的作用远不止状态管理吗? 你是否想要了解 Redux 的工作原理? 让我们深入研究 ...
摘要:相关配置请参考中文文档。关于的更多使用方法及理解需要详细具体讲解,涉及篇幅较大,本文暂不涉及,有兴趣可以看文档中文文档,我会整理后再单独章节分享接下来我们将编写路由组件这与有一些差别,原来的方法已经不再使用,在中或组件从中引入。 相信很多刚入坑React的小伙伴们有一个同样的疑惑,由于React相关库不断的再进行版本迭代,网上很多以前的技术分享变得不再适用。比如react-...
阅读 2739·2021-10-11 11:08
阅读 1456·2021-09-30 09:48
阅读 1012·2021-09-22 15:29
阅读 1003·2019-08-30 15:54
阅读 952·2019-08-29 15:19
阅读 508·2019-08-29 13:12
阅读 3129·2019-08-26 13:53
阅读 911·2019-08-26 13:28