Redux教程

小程序

  • JS-SDK最初解决的就是移动页面能力不足的问题。

  • 小程序的运行环境分为渲染层和逻辑层。

运行环境

Redux教程

  • Redux教程(一):其设计思想就两句话。

    (1)Web应用是一个状态机,视图与状态是一一对应的。

    (2)所有的状态,保存在一个对象里面。

    • Store 应用数据容器

      import { createStore } from 'redux'
      const store = createStore(reducer) // 接收一个函数作为参数
      
    • State 对象包含所有数据,某个时点的Store快照

      const state = store.getState()
      
    • Action 就是View发出的通知,修改State状态

      const action = {
          type: 'ADD_TODO',
          payload: 'Learn Redux'
      }
      

      改变State的唯一办法,就是Action。它会运送数据到Store

    • Action Creator 为避免手写Action的麻烦,定义的一种用于生成Action的函数

      const ADD_TODO = '添加 TODO'
      
      function addTodo(text) {
          return {
              type: ADD_TODO,
              text
          }
      }
      
      const action = addTodo('Learn Redux')
      
    • store.dispatch() 是View发出Action的唯一方法

      store.dispatch({
          type: 'ADD_TODO',
          payload: 'Learn Redux'
      })
      
      // 结合 Action Creator
      store.dispatch(addTodo('Learn Redux'))
      
    • Reducer 在Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫做 Reducer

      Reducer 是一个函数,接收Action和当前的State作为参数,返回一个新的State。

      const initialState = { num: 0 }
      const reducer = (state = initialState, action) => {
          switch(action.type) {
              case 'ADD': 
                  return {
                      ...state,
                      num: state.num + action.payload
                  }
              default:
                  return state
          }
      }
      
      const state = reducer(initialState, {
          type: 'ADD',
          payload: 2
      })
      // 实际应用中store.dispatch会触发`Reducer`自动执行。
      
      const actions = [
        { type: 'ADD', payload: 0 },
        { type: 'ADD', payload: 1 },
        { type: 'ADD', payload: 2 }
      ];
      
      // Reducer是纯函数,可以保证同样的state,可以作为数组对象的参数
      const total = actions.reduce(reducer, initialState); // { num:3 }
      

      **自己的理解:**创建一个全局的数据容器store,这个容器需要一个reducer函数,这个函数决定了我们如何去修改state快照数据。通过store我们可以获取数据快照state,如果要修改state数据,那就可以使用dispatch一个action,这个action是一个对象,包含type、payload等信息,为避免手写action的麻烦,会使用action creator。

    • store.subscribe() 设置监听函数,state变化则执行

      // 把view更新函数放入listen,就会实现view的自动更新。
      let unsubscribe = store.subscribe(listener) // 设置监听
      
      // 调用返回的这个函数就可以解除监听
      unsubscribe();
      
    • Store 的实现

      const createStore (reducer) => {
          let state;
          let listeners = [];
          
          // 获取store的快照
          const getState = () => state;
          
          // 提交数据修改
          const dispatch = (action) => {
              state = reducer(state, action);
              listeners.forEach(listener => listener());
          };
          
          // 监听store
          const subscribe = (listener) => {
              listener.push(listener);
              return () => {
                  listeners = listeners.filter(l => l !== listener);
              }
          };
          
          dispatch({});
          
          return { getState, dispatch, subscribe };    
      }
      
  • Redux教程(二):中间件和异步操作

    Redux基本操作,用户发出Action,Reducer函数算出State,View重新渲染。思考异步操作如何解决?那就得用中间件(middleware)。

    • 中间件

      // 使用中间件
      import { applyMiddleware, createStore } from 'redux'
      import createLogger from 'redux-logger'
      const logger = createLogger()
      
      // 增强store.dispatch()功能
      const store = createStore(reducer, applyMiddleware(logger))
      

      注意点一:createStore方法可以接受整个应用的初始状态作为参数。

      const store = createStore(reducer, initial_state, applyMiddleware(logger))
      

      注意点二:中间件的次序。

      const store = createStore(reducer, applyMiddleware(thunk, promise, logger))
      

      异步操作至少要送出两个Action:用户触发的第一个Action,这个跟同步操作一样,没有问题;如何才能在操作结束时,系统自动送出第二个 Action 呢?

      export function fetchFriends() {
          return (dispatch) => {
              // 触发一次dispatch
              dispatch({ type: 'FETCH_FRIENDS' });
              return fetch('http://xxxx')
              	.then(res => res.json())
              	.then(json => {
                  	dispatch({ type: 'FETCH_FRIENDS', payload: json });
              })
          }
      }
      
      // 使用:
      store.dispatch(fetchFriends())
      store.dispatch(fetchFriends()).then(() => {
          console.log(store.getState())
      })
      

      代码使用redux-thunk中间件,改造store.dispatch,使得后者可以接受函数作为参数。

      因此,异步操作的第一种解决方案就是,写出一个返回函数的 Action Creator,然后使用redux-thunk中间件改造store.dispatch

      import { createStore, applyMiddleware } from 'redux';
      import thunk from 'redux-thunk';
      import reducer from './reducers';
      
      // Note: this API requires redux@>=3.1.0
      const store = createStore(
        reducer,
        applyMiddleware(thunk)
      );
      

React哲学

  1. 将设计好的UI划分为组件层级,一个组件只能负责一个功能。

  2. 用React创建一个静态版本,在静态版本中尽量不使用state。

  3. 确定state(随着时间发生改变,且无法由其他数据计算而来)的最小表示。

  4. 确定state放置的位置,共同所有者组件或者比它层级更高的组件应该拥有该 state。