资讯专栏INFORMATION COLUMN

快速理解redux

stdying / 1146人阅读

摘要:高阶组件以下的所有子组件都可以直接从中获取数据。所以,修改数据的函数出现了即所有的数据都必须通过调用修改。

redux 只是一个状态管理 简述

本篇文章主要说明redux的基本原理以及如何使用

阅读前需了解(本文中仅作简单描述,详细了解请自行Google)

纯函数
符合以下两点性质的函数即为纯函数

函数执行不改变外部变量

函数的输出结果仅依赖于输入参数

高阶组件

即一个函数,接收一个组件作为参数,输出一个新组件

观察者模式

即发布订阅模式,可以理解为给一个事件绑定多个函数,事件触发时多个绑定函数全部执行

react基础

react官方中文文档

wepy基础(有vue基础也可以)

wepy官方文档

redux react中的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 也可以用这种模式了:

/**
*@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的结合 简述 相信很多前端开发者都听说或使用过react-redux,我曾写过一篇关于快速理解redux的文章,虽说是快...

    MoAir 评论0 收藏0
  • 深入理解redux

    摘要:深入简述在快速理解中,我简单的介绍了的基础内容,本篇文章中,我们将再度深入。二修改我曾在快速理解中提起,为了解决模块组件之间需要共享数据和数据可能被任意修改导致不可预料的结果的矛盾,团队创建了。 深入Redux 简述 在快速理解redux中,我简单的介绍了redux的基础内容,本篇文章中,我们将再度深入redux。 redux解决的问题 数据和函数的层层传递 多个组件同时修改某全局变...

    pekonchan 评论0 收藏0
  • 从设计的角度看 Redux

    摘要:协调状态的这三个方面是前端开发的重要组成部分,对这项任务有不同程度的支持。这使得保持高度统一。的真正威力到目前为止,看上去只是的辅助工具。在的术语中这称之为派发动作。撤销重做流行的撤销重做功能需要系统级规划。 想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你! 你知道 Redux 真正的作用远不止状态管理吗? 你是否想要了解 Redux 的工作原理? 让我们深入研究 ...

    fantix 评论0 收藏0
  • react+react-router4+redux最新版构建分享

    摘要:相关配置请参考中文文档。关于的更多使用方法及理解需要详细具体讲解,涉及篇幅较大,本文暂不涉及,有兴趣可以看文档中文文档,我会整理后再单独章节分享接下来我们将编写路由组件这与有一些差别,原来的方法已经不再使用,在中或组件从中引入。       相信很多刚入坑React的小伙伴们有一个同样的疑惑,由于React相关库不断的再进行版本迭代,网上很多以前的技术分享变得不再适用。比如react-...

    weapon 评论0 收藏0
  • 前端面试总结

    摘要:基础浏览器渲染机制水平居中垂直居中数组的几个方法对比闭包作用域原型与原型链继承的介绍事件冒泡与捕获只支持事件冒泡不支持事件捕获,如何在上实现事件捕获运行机制相关介绍你经常用到的的新特性方法网络请求响应分别有哪些头字段,有什么作用缓存相关响 基础 浏览器渲染机制 CSS 水平居中、垂直居中BFC 数组的几个方法对比闭包作用域this原型与原型链、继承的介绍事件冒泡与捕获(IE6只支持事件...

    邹立鹏 评论0 收藏0

发表评论

0条评论

stdying

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<