手动实现一个redux

分为以下几步:
1、修改数据通过dispatch来修改
2、抽离store,数据抽象出来一个 createStore,它可以产生 store,里面包含 getState 和 dispatch 函数
3、观察者模式监控数据
4、共享结构对象提高性能
5、合并方法,stateChanger 为 reducer,定义了 reducer 只能是纯函数,功能就是负责初始 state,和根据 state 和 action 计算具有共享结构的新的 state
在开发过程中如果有共享状态可以被随意的修改是很危险的,

第一步

定义一个dispatch函数专门负责数据的修改,数据的修改都要经过这个dispatch函数
let appState = {
title: {
text: ‘React.js 小书’,
color: ‘red’,
},
content: {
text: ‘React.js 小书内容’,
color: ‘blue’
}
}

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

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
}

renderApp(appState) // 首次渲染页面
dispatch({ type: ‘UPDATE_TITLE_TEXT’, text: ‘《React.js 小书》’ }) // 修改标题文本
dispatch({ type: ‘UPDATE_TITLE_COLOR’, color: ‘blue’ }) // 修改标题颜色
renderApp(appState) // 把新的数据渲染到页面上

第二步

抽离store,用来专门生产这种 state 和 dispatch 的集合
function createStore (state, stateChanger) {
const getState = () => state
const dispatch = (action) => stateChanger(state, action)
return { getState, dispatch }
}

代码如下:
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)

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

第三步

发现每次修改数据都要的手动去渲染数据
很麻烦,这里代用观察者模式,修改数据之后自动渲染
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’ }) // 修改标题颜色

第四步

之前的例子有比较严重的性能问题,每次只修改title,content也会重新渲染,很浪费性能,用共享结构对象来优化
function createStore (state, stateChanger) {
const listeners = []
const subscribe = (listener) => listeners.push(listener)
const getState = () => state
const dispatch = (action) => {
state = stateChanger(state, action) // 覆盖原对象
listeners.forEach((listener) => listener())
}
return { getState, dispatch, subscribe }
}

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
}

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’:
return { // 构建新的对象并且返回
…state,
title: {
…state.title,
text: action.text
}
}
case ‘UPDATE_TITLE_COLOR’:
return { // 构建新的对象并且返回
…state,
title: {
…state.title,
color: action.color
}
}
default:
return state // 没有修改,返回原来的对象
}
}

const store = createStore(appState, stateChanger)
let oldState = store.getState() // 缓存旧的 state
store.subscribe(() => {
const newState = store.getState() // 数据可能变化,获取新的 state
renderApp(newState, oldState) // 把新旧的 state 传进去渲染
oldState = newState // 渲染完以后,新的 newState 变成了旧的 oldState,等待下一次数据变化重新渲染
})

renderApp(store.getState()) // 首次渲染页面
store.dispatch({ type: ‘UPDATE_TITLE_TEXT’, text: ‘《React.js 小书》’ }) // 修改标题文本
store.dispatch({ type: ‘UPDATE_TITLE_COLOR’, color: ‘blue’ }) // 修改标题颜色

第五步

appState 和 stateChanger可以合并到一起

最终代码如下:
const appState = {
title: {
text: ‘React.js 小书’,
color: ‘red’,
},
content: {
text: ‘React.js 小书内容’,
color: ‘blue’
}
}
function renderApp (appState,oldAppState = {}) {
if (appState === oldAppState) return // 数据没有变化就不渲染了
console.log(‘render app…’)
renderTitle(appState.title, oldAppState.title)
renderContent(appState.content, oldAppState.content)
}
function renderTitle (title, oldTitle = {}) {
if (title === oldTitle) return // 数据没有变化就不渲染了
console.log(‘render title…’)
const titleDOM = document.getElementById(‘title’)
titleDOM.innerHTML = title.text
titleDOM.style.color = title.color
}

function renderContent (content, oldContent = {}) {
if (content === oldContent) return // 数据没有变化就不渲染了
console.log(‘render content…’)
const contentDOM = document.getElementById(‘content’)
contentDOM.innerHTML = content.text
contentDOM.style.color = content.color
}
function stateChanger(state,action){
if (!state) {
return {
title: {
text: ‘React.js 小书’,
color: ‘red’,
},
content: {
text: ‘React.js 小书内容’,
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;
}
}
const store = createStore(stateChanger)
let oldState = store.getState() // 缓存旧的 state
renderApp(oldState)
store.subscribe(()=>{
const newState = store.getState() // 数据可能变化,获取新的 state
renderApp(store.getState(),oldState)
oldState = newState // 渲染完以后,新的 newState 变成了旧的 oldState,等待下一次数据变化重新渲染
})

store.dispatch({ type: ‘UPDATE_TITLE_TEXT’, text: ‘《React.js 小书》’ })
store.dispatch({ type: ‘UPDATE_TITLE_COLOR’, color: ‘blue’ }) // 修改标题颜色

function createStore(reducer){
let state = null
const listeners = []
const subscribe=(listener)=>listeners.push(listener)
const getState=()=>state
const dispatch=(action)=>{
state = reducer(state,action)
listeners.forEach((listener) => listener())
}
dispatch({}) // 初始化 state
return {getState,dispatch,subscribe}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值