createStore

react组件更新一定是 setState触发的,
props的改变,也是父级调用了 setSatte,子级的 props改变了

  1. // 创建一个仓库
  2. function createStore(reducer) {
  3. let store // createStore 不提供初始状态,默认 undefined
  4. let eventPool = [];
  5. // 返回当前的 store
  6. function getState() {
  7. return store
  8. }
  9. /**
  10. * dispatch派发一个动作,规定想要修改的状态
  11. * 约定:只能通过派发动作的方式来修改 store
  12. *
  13. * action 要对 store仓库里面的状态做什么操作?
  14. * action就是一个普通的对象,至少有一个 type属性,表示动作的类型
  15. * 约定:参数都再放在 payload里面
  16. */
  17. function dispatch(action) {
  18. store = reducer(store, action)
  19. eventPool.forEach(r => {
  20. if(typeof r === 'function') r()
  21. })
  22. }
  23. // subscribe方法每次调用都会返回一个取消订阅的方法
  24. function subscribe(listener) {
  25. eventPool.push(listener)
  26. return () => {
  27. // 调用一次后就删除
  28. eventPool = eventPool.filter(r => r !== listener)
  29. }
  30. }
  31. // createStore时,先派发一个动作初始化 state,返回一个默认的 store
  32. dispatch({type: '@@TYPE/REDUX_INIT'})
  33. return { getState, dispatch, subscribe }
  34. }
  35. export default createStore

reducer

reducer方法修改 store,返回一个新的 store

  1. const UPDATE_TITLE_COLOR = 'UPDATE_TITLE_COLOR'
  2. const UPDATE_TITLE_TEXT = 'UPDATE_TITLE_TEXT'
  3. const UPDATE_CONTENT_COLOR = 'UPDATE_CONTENT_COLOR'
  4. const UPDATE_CONTENT_TEXT = 'UPDATE_CONTENT_TEXT';
  5. const initState = {
  6. title: {
  7. color: 'red',
  8. text: '标题'
  9. },
  10. content: {
  11. color: 'green',
  12. text: '默认的内容'
  13. }
  14. }
  15. // reducer提供一个初始的参数 state,必须要在 createStore内部调用一次 dispatch
  16. function reducer(state = initState, action) {
  17. const { type, color, text} = action
  18. switch(type) {
  19. case UPDATE_TITLE_COLOR:
  20. return {
  21. ...state,
  22. title: {...state.title, color}
  23. }
  24. case UPDATE_TITLE_TEXT:
  25. return {
  26. ...state,
  27. title: {...state.title, text}
  28. }
  29. case UPDATE_CONTENT_COLOR:
  30. return {
  31. ...state,
  32. content: {...state.content, color}
  33. }
  34. case UPDATE_CONTENT_TEXT:
  35. return {
  36. ...state,
  37. content: {...state.content, text}
  38. }
  39. default:
  40. return state
  41. }
  42. // return newState
  43. }

createStore(reducer)

  1. import createStore from './createStore'
  2. // 通过 dispatch派发动作去修改 store
  3. const {getState, dispatch, subscribe} = createStore(reducer)
  4. render()
  5. function render() {
  6. renderApp(getState())
  7. }
  8. const unsubscribe = subscribe(render) // 订阅事件,store改变,重新执行 render()
  9. // 无效,不能先渲染,缺点:store改变不能重新渲染
  10. // 例如:多个组件订阅,一个组件修改后,其他组件不重新渲染
  11. // dispatch({type: UPDATE_TITLE_COLOR, color: '#90f'})
  12. // dispatch({type: UPDATE_CONTENT_TEXT, text: '一树春伸万花开'})
  13. // 优化:需要重新 getState渲染,再次优化:dispatch自动渲染,发布订阅模式
  14. // renderApp(getState())
  15. setTimeout(() => {
  16. dispatch({type: UPDATE_TITLE_COLOR, color: '#90f'})
  17. dispatch({type: UPDATE_CONTENT_TEXT, text: '一树春伸万花开'})
  18. unsubscribe() // 取消订阅,后面的就不执行了
  19. dispatch({type: UPDATE_CONTENT_TEXT, text: '万紫千红总是春'})
  20. }, 1000)

App

image.png

  1. function renderApp(store) {
  2. const { title, content } = store
  3. renderTitle(title)
  4. renderContent(content)
  5. }
  6. function renderTitle(data) {
  7. const title = document.getElementById('title');
  8. const { text, color } = data;
  9. title.innerHTML = text;
  10. title.style.color = color;
  11. }
  12. function renderContent(content) {
  13. const main = document.getElementById('main')
  14. const { text, color } = content;
  15. main.innerHTML = text
  16. main.style.color = color;
  17. }