createStore
- 專門產生 state 以及 dispatch 的集合,別的 App 也可用來這種模式。
- createStore 接受兩個參數:
- state: 用來描述狀態。
- stateChanger,用來描述狀態會根據 action 發生什麼變化,也就是 dispatch。
- createStore 回傳:
- getState: 就是回傳 state 數據。
- dispatch: 用於修改數據,一樣接收 action,把 state 以及 action 傳給 stateChanger,那麼 stateChanger 可以根據 action 修改 state。
function createStore (state, stateChanger) {
const getState = () => state
const dispatch = (action) => stateChanger(state, action)
return { getState, dispatch }
}
新增 createStore、修改 dispatch 為 stateChanger
const appState = {
title: {
text: 'React.js 小書',
color: 'red',
},
content: {
text: 'React.js 小書內容',
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
}
// createStore
function createStore (state, stateChanger) {
const getState = () => state
const dispatch = (action) => stateChanger(state, action)
return { getState, dispatch }
}
// 將 dispatch 修改為 stateChanger
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)
// appState 改為 store
renderApp(store.getState()) // first render
store.dispatch({type: 'UPDATE_TITLE_TEXT', text: 'React 小書'}) // 修改內容
store.dispatch({type: 'UPDATE_TITLE_COLOR', color: 'blue'}) // 修改標題顏色
renderApp(store.getState()) // redner again
監控數據變化
為了不要每次用 dispatch 修改數據的時候都要手動調用 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 }
}
每當透過 dispatch
修改數據的時候,就會呼叫監聽函數,便能在每次數據變化的時候重新渲染,這就是監聽 subscribe
的概念。
const store = createStore(appState, stateChanger)
store.subscribe(() => renderApp(store.getState())) // 監聽數據變化
subscribe 的優點
- 每次數據變化的時候重新渲染畫面。
- 可以拿相同的數據渲染別的畫面。
const store = createStore(appState, stateChanger)
store.subscribe(() => renderApp(store.getState()))
store.subscribe(() => renderApp2(store.getState()))
store.subscribe(() => renderApp3(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()) // first render
store.dispatch({ type: 'UPDATE_TITLE_TEXT', text: '《React.js 小書》' }) // 修該標題文字
store.dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' }) // 修改標題顏色
總結
- 有一個比較通用的
createStore
,可以產生新定義的數據類型。 store
,透過store.getState
,可獲取共享的狀態。store.subscribe
,監聽數據狀態被修改,並且進行後續操作,例如畫面渲染。