redux-基本概念API
redux
基本概念API
Store
Store保存数据的地方,整个应用只有一个Store
createStore可以接受一个函数作为参数,返回生成的新store
import { createStore } from 'redux';
const store = createStore(fn);
State
Store包含所有数据,获得了某个时间点的数据,需要生成快照,这种数据叫做State
获取当前时刻的State
import { createStore } from 'redux';
const store = createStore(fn);
const state = store.getState();
一个State对应一个View,反之亦然
Action
State变化会导致view变化,用户只能接触到view,不能接触到State
Action是一个对象,其中的type必须,其他属性可以自由设置
规范:https://github.com/acdlite/flux-standard-action
const action = {
  type: 'ADD_TODO',
  payload: 'Learn Redux'
};
Action描述正在发生的事,改变State的唯一办法就是使用action,它会运送数据到Store
Action Creator
定义一个函数生成action,Action Creator
const ADD_TODO = '添加 TODO';
function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}
const action = addTodo('Learn Redux');
store.dispatch()
store.dispatch()是 View 发出 Action 的唯一方法
import { createStore } from 'redux';
const store = createStore(fn);
store.dispatch({
  type: 'ADD_TODO',
  payload: 'Learn Redux'
});
接收一个action对象作为参数,然后发送出去
改写为
store.dispatch(addTodo('Learn Redux'));
Reducer
Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。
这种state的计算过程叫做Reducer
Reducer是一个函数,接收新的Action 和当前的state作为参数,返回新的state
const reducer = function (state, action) {
  // ...
  return new_state;
};
初始状态可作为state的默认值
const defaultState = 0;
const reducer = (state = defaultState, action) => {
  switch (action.ytpe) {
    case 'ADD':
      return state + action.payload;
    default: 
      return state;
  }
};
const state = reducer(1, {
  type: 'ADD',
  payload: 2
})
reducer函数收到名为ADD的 Action 以后,就返回一个新的 State,作为加法的计算结果。
其他运算的逻辑(比如减法),也可以根据 Action 的不同来实现
store.dispatch方法会触发 Reducer 的自动执行
Store 需要知道 Reducer 函数,做法就是在生成 Store 的时候,将 Reducer 传入createStore方法。
import { createStore } from 'redux';
const store = createStore(reducer);
以后每当store.dispatch发送过来一个新的 Action,就会自动调用 Reducer,得到新的 State。
可以接收数组的recuce
const actions = [
  { type: 'ADD', payload: 0 },
  { type: 'ADD', payload: 1 },
  { type: 'ADD', payload: 2 }
];
const total = actions.reduce(reducer, 0); // 3
纯函数
Reducer函数里不能改变state,只能返回全新的对象
// State 是一个对象
function reducer(state, action) {
  return Object.assign({}, state, { thingToChange });
  // 或者
  return { ...state, ...newState };
}
// State 是一个数组
function reducer(state, action) {
  return [...state, newItem];
}
store.subscribe()
使用store.subscribe设置监听函数,一旦state变化,就会执行这个函数
import { createStore } from 'redux';
const store = createStore(reducer);
store.subscribe(listener);
只要把view的更新函数,放到listener中,就会实现View的自动渲染,在React中就是render/setState方法
store.subscribe方法返回一个函数,调用它就可以解除监听
let unsubscribe = store.subscribe(() =>
  console.log(store.getState())
);
unsubscribe();
Store 的实现
Store提供了三个方法
- store.getState()
- store.dispatch()
- store.subscribe()
import { createStore } from 'redux';
let { subscribe, dispatch, getState } = createStore(reducer);
createStore方法还可以接受第二个参数表示State的最初状态,通常是服务器给出的
let store = createStore(todoApp, window.STATE_FROM_SERVER)
window.STATE_FROM_SERVER就是最初状态,如果提供了这个参数,就会覆盖Reducer函数的默认初始值
下面是createStore的一个简单实现
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({});
  return { getState, dispatch, subscribe };
};
Reducer 的拆分
Reducer函数负责生产state,整个应用都只有一个State对象,包含所有数据,大型应用会非常庞大
const chatReducer = (state = defaultState, action = {}) => {
  const { type, payload } = action;
  switch (type) {
    case ADD_CHAT:
      return Object.assign({}, state, {
        chatLog: state.chatLog.concat(payload)
      });
    case CHANGE_STATUS:
      return Object.assign({}, state, {
        statusMessage: payload
      });
    case CHANGE_USERNAME:
      return Object.assign({}, state, {
        userName: payload
      });
    default: return state;
  }
};
代码中三种action分别改变三种属性
- ADD_CHAT:chatLog属性
- CHANGE_STATUS:statusMessage属性
- CHANGE_USERNAME:userName属性
三种属性没有联系,这样可以把reduce函数拆分,不同的函数处理不同的属性,然后合并
const chatReducer = (state = defaultState, action = {}) => {
  return {
    chatLog: chatLog(state.chatLog, action),
    statusMessage: statusMessage(state.statusMessage, action),
    userName: userName(state.userName, action)
  }
};
Reducer 函数被拆成了三个小函数,每一个负责生成对应的属性。
这种拆分与 React 应用的结构相吻合:一个 React 根组件由很多子组件构成。这就是说,子组件与子 Reducer 完全可以对应。
Redux 提供了一个combineReducers方法,用于 Reducer 的拆分。
你只要定义各个子 Reducer 函数,然后用这个方法,将它们合成一个大的 Reducer。
import { combineReducers } from 'redux';
const chatReducer = combineReducers({
  chatLog,
  statusMessage,
  userName
})
export default todoApp;
这种写法有一个前提,就是 State 的属性名必须与子 Reducer 同名。如果不同名,就要采用下面的写法。
const reducer = combineReducers({
  a: doSomethingWithA,
  b: processB,
  c: c
})
// 等同于
function reducer(state = {}, action) {
  return {
    a: doSomethingWithA(state.a, action),
    b: processB(state.b, action),
    c: c(state.c, action)
  }
}
combineReducers()做的就是产生一个整体的 Reducer 函数。
该函数根据 State 的 key 去执行相应的子 Reducer,并将返回结果合并成一个大的 State 对象。
combineReducers简单实现
const combineReducers = reducers => {
  return (state = {}, action) => {
    return Object.keys(reducers).reduce(
      (nextState, key) => {
        nextState[key] = reducers[key](state[key], action);
        return nextState;
      },
      {} 
    );
  };
};
可以放到一个文件里统一引入
import { combineReducers } from 'redux'
import * as reducers from './reducers'
const reducer = combineReducers(reducers)
redux工作流

首先用户发出action
store.dispatch(action);
然后,Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action。 Reducer 会返回新的 State 。
let nextState = todoApp(previousState, action);
State 一旦有变化,Store 就会调用监听函数。
// 设置监听函数
store.subscribe(listener);
listener可以通过store.getState()得到当前状态。如果使用的是 React,这时可以触发重新渲染 View。
function listerner() {
  let newState = store.getState();
  component.setState(newState);   
}
例子:计数器
const Counter = ({ value }) => (
  <h1>{value}</h1>
);
const render = () => {
  ReactDOM.render(
    <Counter value={store.getState()}/>,
    document.getElementById('root')
  );
};
store.subscribe(render);
render();
const Counter = ({ value }) => (
  <h1>{value}</h1>
  <button onClick={onIncrement}>+</button>
  <button onClick={onDecrement}>-</button>
);
const reducer = (state = 0, action) => {
  switch (action.type) {
    case 'INCREMENT': return state + 1;
    case 'DECREMENT': return state - 1;
    default: return state;
  }
};
const store = createStore(reducer);
const render = () => {
  ReactDOM.render(
    <Counter
      value={store.getState()}
      onIncrement={() => store.dispatch({type: 'INCREMENT'})}
      onDecrement={() => store.dispatch({type: 'DECREMENT'})}
    />,
    document.getElementById('root')
  );
};
render();
store.subscribe(render);
 
                    
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号