Skip to content

Latest commit

 

History

History
76 lines (59 loc) · 2.81 KB

02.完成计数器App.md

File metadata and controls

76 lines (59 loc) · 2.81 KB

完成计数器App

上篇我们完成了计数器的store的构建,那么现在我们要做的就是将这个store表达成正确的UI

redux的store上有三个方法

  • getState,获得此时此刻App的state(状态)。store.getState()
  • dispatch,使用action。用法是store.dispatch(action)
  • subscribe,订阅。store.subscribe(function)每当state改变时,执行function。在react项目里大多用于触发重渲染(render)。

crateStore方法如何构建store感兴趣的同学,这里是源代码:

const createStore = (reducer) => {
  let state
  let listeners = []

  const getState = () => state
  
  const dispatch = (action) => {
    state = reducer(state, action)
    listeners.forEach(listener => listener())
  }

  const subscribe = (listener) => {
    listeners.push(listener)
    return () => {
      listeners = listeners.filter(l => l !== listener)
    }
  }

  dispatch({}) // 生成初始state

  return { getState, dispatch, subscribe }
}

那么开始吧:

//state => UI,函数式组件简洁
const Counter = () =>
  <div>
    <div>
      {store.getState()}
    </div>
    <button onClick={() => store.dispatch({type: "PLUS"})}> + </button>
    <button onClick={() => store.dispatch({type: "MINUS"})}> - </button>
  </div>
//定义渲染函数。注意es6的简写,相当于function(){return ...}
const render = () =>
  ReactDOM.render(<Counter />, document.body)
//订阅
store.subscribe(render)
//初始需要执行一次
render()

梳理一下:

  • render()渲染了计数器
  • 每当用户点击“+”和“-”时,会触发action {type: "PLUS"}{type: "MINUS"}
  • reducer解析action对state的改变
  • state改变,于是store.subscribe(render)触发了render(),计数器重新渲染
  • store.getState()重新读取此时的state,显示新的计数

真实项目不会把所有代码写在一个文件里,也一般不使用store.subscribe(render)这种低效的方式(再细小的state改变都会导致整个App的重渲染)。而会使用react-redux库来更好地完成State => UI。我们会在接下来的篇幅讨论。

事实上当你开始使用react-redux写项目后,dispatch可能会是你唯一接触的store方法了,所以不用特别费心。但我相信了解redux在底层是如何运作是运用好redux的必要一环。

作业:尝试完成上一章的todo-list App。

样式上不用一模一样,只需让它能正常使用。答案见demo。

下一章,让我们讨论另一个当初最让我困惑的问题:真实redux项目是如何规划文件结构的?怎样写出整洁可扩展的redux项目?

下一章