實作 Redux(二):抽離 store 以及監控數據的變化


Posted by YongChenSu on 2020-12-14

createStore

  • 專門產生 state 以及 dispatch 的集合,別的 App 也可用來這種模式。
  • createStore 接受兩個參數:
    1. state: 用來描述狀態。
    2. stateChanger,用來描述狀態會根據 action 發生什麼變化,也就是 dispatch。
  • createStore 回傳:
    1. getState: 就是回傳 state 數據。
    2. 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 的優點

  1. 每次數據變化的時候重新渲染畫面。
  2. 可以拿相同的數據渲染別的畫面。
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' }) // 修改標題顏色

總結

  1. 有一個比較通用的 createStore,可以產生新定義的數據類型。
  2. store,透過 store.getState,可獲取共享的狀態。
  3. store.subscribe,監聽數據狀態被修改,並且進行後續操作,例如畫面渲染。

參考資源


#程式導師實驗計畫第四期 #前端 #React #react book #Redux #store







Related Posts

[Day01] immutable

[Day01] immutable

CH4. 老手看函式:理解函式呼叫

CH4. 老手看函式:理解函式呼叫

eslint 是什麼?

eslint 是什麼?


Comments