redux详解
简单代码
const appState = {
title: {
text: '这是title',
color: 'red',
},
content: {
text: '这是content',
color: 'blue'
}
}
<div id='title'></div>
<div id='content'></div>
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)

事情有这么简单?
loadDataFromServer()
doSomething()
doSomthingMore()
doSomthingBad()
// ...
renderApp(appState)
数据的不可预测性
矛盾
模块(组件)之间需要共享数据数据
可能被任意修改导致不可预料的结果
限制数据修改
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({ type: 'UPDATE_TITLE_TEXT', text: '修改title' })
dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' })
renderApp(appState)
所有对数据的修改必须进过dispatch
抽出store
function createStore (state, stateChanger) {
const getState = () => state
const dispatch = (action) => stateChanger(state, action)
return { getState, dispatch }
}
const store = createStore(appState, stateChanger)
renderApp(store.getState())
store.dispatch({ type: 'UPDATE_TITLE_TEXT', text: '修改title' })
store.dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' })
renderApp(store.getState())
每次都需要手动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 }
}
const store = createStore(appState, stateChanger)
store.subscribe(() => renderApp(store.getState()))
renderApp(store.getState())
store.dispatch({ type: 'UPDATE_TITLE_TEXT', text: '修改title' })
store.dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' })
纯函数
一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用,我们就把这个函数叫做纯函数
const a = 1
const foo = (b) => a + b
foo(2)
const a = 1
const foo = (x, b) => x + b
foo(1, 2)
const foo = (obj, b) => {
obj.x = 2
return obj.x + b
}
const counter = { x: 1 }
foo(counter, 2)
counter.x
const foo = (b) => {
const obj = { x: 1 }
obj.x = 2
return obj.x + b
}
页面性能
function renderApp (appState) {
console.log('render app...')
renderTitle(appState.title)
renderContent(appState.content)
}
function renderTitle (title) {
console.log('render title...')
const titleDOM = document.getElementById('title')
titleDOM.innerHTML = title.text
titleDOM.style.color = title.color
}
function renderContent (content) {
console.log('render content...')
const contentDOM = document.getElementById('content')
contentDOM.innerHTML = content.text
contentDOM.style.color = content.color
}
const store = createStore(appState, stateChanger)
store.subscribe(() => renderApp(store.getState()))
renderApp(store.getState()) // 首次渲染页面
store.dispatch({ type: 'UPDATE_TITLE_TEXT', text: '修改title' })
store.dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' })

简单点 加个判断
function renderApp (newAppState, oldAppState = {}) {
if (newAppState === oldAppState) return // 数据没有变化就不渲染了
}
function renderTitle (newTitle, oldTitle = {}) {
if (newTitle === oldTitle) return // 数据没有变化就不渲染了
}
function renderContent (newContent, oldContent = {}) {
if (newContent === oldContent) return // 数据没有变化就不渲染了
}
const store = createStore(appState, stateChanger)
let oldState = store.getState()
store.subscribe(() => {
const newState = store.getState()
renderApp(newState, oldState)
oldState = newState
})
达到效果了么?
对象拷贝
浅拷贝(创建新对象的时候只需要对发生变化的属性进行变更)
let appState = {
title: {
text: '这是title',
color: 'red',
},
content: {
text: '这是content',
color: 'blue'
}
}
let newAppState = Object.assign({}, appState);
newAppState.title = Object.assign({}, newAppState.title, {text: '修改title'})
优化后的代码
function stateChanger (state, action) {
let newAppState = {}
switch (action.type) {
case 'UPDATE_TITLE_TEXT':
newAppState = Object.assign({}, state)
newAppState.title = Object.assign({}, newAppState.title, {text: action.text})
return newAppState
case 'UPDATE_TITLE_COLOR':
newAppState = Object.assign({}, state)
newAppState.title = Object.assign({}, newAppState.title, {color: action.color})
return newAppState
default:
return state
}
}
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 }
}
const store = createStore(appState, stateChanger)
let oldState = store.getState()
store.subscribe(() => {
const newState = store.getState()
renderApp(newState, oldState)
oldState = newState
})
代码再次简化
合并appState和stateChanger
function stateChanger (state, action) {
if (!state) {
return {
title: {
text: '这是title',
color: 'red',
},
content: {
text: '这是content',
color: 'blue'
}
}
}
let newAppState = {}
switch (action.type) {
case 'UPDATE_TITLE_TEXT':
newAppState = Object.assign({}, state)
newAppState.title = Object.assign({}, newAppState.title, {text: action.text})
return newAppState
case 'UPDATE_TITLE_COLOR':
newAppState = Object.assign({}, state)
newAppState.title = Object.assign({}, newAppState.title, {color: action.color})
return newAppState
default:
return state
}
}
代码再次简化
改写createStore
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 }
}
const store = createStore(stateChanger)
悄悄换了参数名
再仔细看下stateChanger这个函数
大功告成
简单的数据依赖demo
数据可随意修改
引入dispatch,修改数据必须使用action
引入createStore,用于产生store,包含了getStore和fispatch
通过store.subscribe ,订阅数据修改,执行事件
由于性能问题,引入对象拷贝(共享结构的对象)
优化stateChanger为纯函数,用于初始state,以及根据action提供新的action
用法
// 定一个 reducer
function reducer (state, action) {
/* 初始化 state 和 switch case */
}
// 生成 store
const store = createStore(reducer)
// 监听数据变化重新渲染页面
store.subscribe(() => renderApp(store.getState()))
// 首次渲染页面
renderApp(store.getState())
// 后面可以随意 dispatch 了,页面自动更新
store.dispatch(...)
谢谢
deck
By Joson Chen
deck
- 308