<Redux>实现MyRedux(一)

说在前面

为了学习redux,仅仅实现了store,createStore,reducer等部分基本功能

实现MyRedux系列

  1. 实现MyRedux(一)
  2. 实现MyRedux(二)
  3. 实现MyRedux(三)

现在开始忘掉一切

首先用create-react-app新建一个项目,修改public/index.html下的页面结构

  <body>
    <div id='title'></div>
    <div id='content'></div>
  </body>

清空src文件夹,新建一个index.js,添加代码代表我们要应用的状态:

const appState = {
  title: {
    text: 'Redux',
    color: 'red',
  },
  content: {
    text: '学习redux',
    color: 'blue'
  }
}

添加渲染函数,会把上面的状态数据渲染到页面上:

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
}

简单的渲染完成了,但是会有一个严重的问题,渲染数据使用的是共享的状态appState,任何人都能修改,如果我们在渲染之前做了其他函数操作,就无法智大东会对appState做了什么事情,也就是为什么要避免全局变量

当我们的不同组件之间需要共享数据,就会产生矛盾:

组件之间共享数据 ❗❗ 数据可能在组件内被任意修改

如果我们学习一下React团队的做法,把操作变复杂

​ 组件之间可以共享、改动数据但是不能直接修改,必须执行我定义的某些函数

定义一个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函数,接收一个参数action,它是一个普通对象,里面包含一个type字段来生命你想干什么,dispatch内的switch会识别这个字段,识别成功的会对appState进行修改

上面的 dispatch 它只能识别两种操作,一种是 UPDATE_TITLE_TEXT 它会用 actiontext 字段去更新 appState.title.text;一种是 UPDATE_TITLE_COLOR,它会用 actioncolor 字段去更新 appState.title.coloraction 里面除了 type 字段是必须的以外,其他字段都是可以自定义的。

如果想要修改appState.title.text,必须调用dispatch

dispatch({ type: 'UPDATE_TITLE_TEXT', text: 'React.js' }) // 修改标题文本
dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' }) // 修改标题颜色

这样就不用的担心别的函数会修改appState,至少是直接修改

原来:

在这里插入图片描述

现在所有的数据想修改必须经过dispatch


抽离出store

现在有了appStatedispatch,可以把他们集中到一个地方,起名叫做store,然后构建一个createStore()函数,用来生产这种statedispatch的集合

function createStore (state, stateChanger) {
  const getState = () => state
  const dispatch = (action) => stateChanger(state, action)
  return { getState, dispatch }
}

createStore接收两个参数,一个是表示状态的state,另一个是stateChanger,它用来描述应用程序状态会根据action发生什么变化,相当于dispatch

createStore返回一个对象,包含两个方法,getState用于获取state的数据,dispatch用于修改数据,和以前一样

现在我的代码可以优化成:

et 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)

renderApp(store.getState()) // 首次渲染页面
store.dispatch({ type: 'UPDATE_TITLE_TEXT', text: 'React.js' }) // 修改标题文本
store.dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' }) // 修改标题颜色
renderApp(store.getState()) // 把新的数据渲染到页面上

然后我们就有个棘手的问题,怎么监控数据的变化,上述代码中,如果我们不调用renderApp,那页面的内容是不会变化的,如果往dispatch中加入renderApp,那我们想通用createStore就不行了,想用一种通用的方式监听数据,需要用到观察者模式:

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 }
}

在方法中定义了一个数组,还有一个subscribe方法,可以通过这个方法传入一个监听函数,并push到数组中,修改了dispatch方法,当它被调用的时候,会遍历数组中的函数,一个个的调用,这就意味着我们可以通过subscribe传入数据变化的监听函数,每次dispatch的时候,监听函数都会被调用

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' }) // 修改标题颜色
// ...后面不管如何 store.dispatch,都不需要重新调用 renderApp

只需要subscribe一次,后面不管怎么dispatchrenderApp都会被重新调用,重新渲染页面,而且观察者模式下同一块数据也可以渲染其他页面。

阶段总结

现在有了通用的createStore,可以产生一种新定义的数据类型store,通过getState获取状态,dispatch修改状态,subscribe监听数据……


最后欢迎大噶进来摸个鱼🐠
在这里插入图片描述

  • 13
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值