createStore
react组件更新一定是 setState触发的,
props的改变,也是父级调用了 setSatte,子级的 props改变了
// 创建一个仓库
function createStore(reducer) {
let store // createStore 不提供初始状态,默认 undefined
let eventPool = [];
// 返回当前的 store
function getState() {
return store
}
/**
* dispatch派发一个动作,规定想要修改的状态
* 约定:只能通过派发动作的方式来修改 store
*
* action 要对 store仓库里面的状态做什么操作?
* action就是一个普通的对象,至少有一个 type属性,表示动作的类型
* 约定:参数都再放在 payload里面
*/
function dispatch(action) {
store = reducer(store, action)
eventPool.forEach(r => {
if(typeof r === 'function') r()
})
}
// subscribe方法每次调用都会返回一个取消订阅的方法
function subscribe(listener) {
eventPool.push(listener)
return () => {
// 调用一次后就删除
eventPool = eventPool.filter(r => r !== listener)
}
}
// createStore时,先派发一个动作初始化 state,返回一个默认的 store
dispatch({type: '@@TYPE/REDUX_INIT'})
return { getState, dispatch, subscribe }
}
export default createStore
reducer
reducer方法修改 store,返回一个新的 store
const UPDATE_TITLE_COLOR = 'UPDATE_TITLE_COLOR'
const UPDATE_TITLE_TEXT = 'UPDATE_TITLE_TEXT'
const UPDATE_CONTENT_COLOR = 'UPDATE_CONTENT_COLOR'
const UPDATE_CONTENT_TEXT = 'UPDATE_CONTENT_TEXT';
const initState = {
title: {
color: 'red',
text: '标题'
},
content: {
color: 'green',
text: '默认的内容'
}
}
// reducer提供一个初始的参数 state,必须要在 createStore内部调用一次 dispatch
function reducer(state = initState, action) {
const { type, color, text} = action
switch(type) {
case UPDATE_TITLE_COLOR:
return {
...state,
title: {...state.title, color}
}
case UPDATE_TITLE_TEXT:
return {
...state,
title: {...state.title, text}
}
case UPDATE_CONTENT_COLOR:
return {
...state,
content: {...state.content, color}
}
case UPDATE_CONTENT_TEXT:
return {
...state,
content: {...state.content, text}
}
default:
return state
}
// return newState
}
createStore(reducer)
import createStore from './createStore'
// 通过 dispatch派发动作去修改 store
const {getState, dispatch, subscribe} = createStore(reducer)
render()
function render() {
renderApp(getState())
}
const unsubscribe = subscribe(render) // 订阅事件,store改变,重新执行 render()
// 无效,不能先渲染,缺点:store改变不能重新渲染
// 例如:多个组件订阅,一个组件修改后,其他组件不重新渲染
// dispatch({type: UPDATE_TITLE_COLOR, color: '#90f'})
// dispatch({type: UPDATE_CONTENT_TEXT, text: '一树春伸万花开'})
// 优化:需要重新 getState渲染,再次优化:dispatch自动渲染,发布订阅模式
// renderApp(getState())
setTimeout(() => {
dispatch({type: UPDATE_TITLE_COLOR, color: '#90f'})
dispatch({type: UPDATE_CONTENT_TEXT, text: '一树春伸万花开'})
unsubscribe() // 取消订阅,后面的就不执行了
dispatch({type: UPDATE_CONTENT_TEXT, text: '万紫千红总是春'})
}, 1000)
App
function renderApp(store) {
const { title, content } = store
renderTitle(title)
renderContent(content)
}
function renderTitle(data) {
const title = document.getElementById('title');
const { text, color } = data;
title.innerHTML = text;
title.style.color = color;
}
function renderContent(content) {
const main = document.getElementById('main')
const { text, color } = content;
main.innerHTML = text
main.style.color = color;
}