redex

745 阅读4分钟

redex基本用法

Store

store是保存数据的地方,它是整个应用的容器,整个应用只能有一个store。

redux提供了createStore来生成store

 import {createStore} from 'redux';const store = createStore(fn); //createStore接收另一个函数为参数,生成一个新的store对象

State

state对象包含整个应用的数据,在应用中可以使用store.getState()得到。

 const state = store.getState(); //这里一个state对应一个view,只要state相同,view就相同

Action

在应用中state的变化会导致view的变化,但是对于用户而言是接触不到state,只能接触到view。所以state的变化必须由view导致的,action的作用就是通知state发生变化的渠道。action是一个对象,type是它的名字,是必须的。

 const action = {  type: 'ADD_LIST', //名称  payload: 'str' //荷载}

Action Creator

从以上的介绍当中发现,view要发送多少种消息就要创建多少个action,现在我们用一个工厂函数来生成Action,即Action Creator。

 const ADD_LIST = '添加列表'function addList(text) { //addLista函数就是一个Action Creator  type: ADD_LIST,  text}const action = addList('template 1')

store.dispatch()

store.dispatch()是view发出action的唯一方法。

 store.dispatch({ //接收一个action对象作为参数,将它发送出去  type: 'ADD_List',  payload: 'templata 1'});//结合Action Creator的写法,可以写为下列形式store.dispatch(addList('template 1'))

Reducer

store接收到action之后,必须给出一个新的state,这样view才会发生变化,这种state的计算过程叫做reducer。reducer是一个函数,它接收action和当前的state作为参数,返回一个新的state。

 const reducer = function (state,action) {  //...  return new_state;}

用下面的实例来解释

 const defaultState = 0;const reducer = (state = defaultState, action) => {  Switch (action.type) {    case 'ADD':        return state + action.payload;    default        return state;  }}const state = reducer(1,{  type: 'ADD',  payload: 1})

在实际的应用当中我们并不用像这样的手动调用,运用store.dispatch方法会触发reducer的自动执行。所以,store在创建的时候,就要将reducer传入createStore中。

 import { createStore } from 'redux';const store = createStore(reducer);

reducer不能改state,只能返回一个全新的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允许使用store.subscribe方法设置监听函数,一旦state发生了变化,就执行这个函数。

 store.subscribe(listener);

简单的说在创建应用的时候,只要把render和setState放入listen中,就会实现view的自动渲染,store.subscribe()返回一个函数,调用这个函数可以解除监听。

 let unsubscribe = store.subscribe(()=>{  //...})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)

下面用实例来解释下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({});​  return { getState, dispatch, subscribe };}

Reducer 的拆分

Reducer 函数负责生成 State。由于整个应用只有一个 State 对象,包含所有数据,对于大型应用来说,这个 State 必然十分庞大,导致 Reducer 函数也十分庞大。

 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;  }};

下面我们将redecer进行拆分(一个react根组件可以由很多子组件构成)

const chatReducer = (state = defaultState, action = {}) => {
  return {
    chatLog: chatLog(state.chatLog, action),
    statusMessage: statusMessage(state.statusMessage, action),
    userName: userName(state.userName, action)
  }
};

redux提供了一个combineReducers方法用于reducer的拆分。

 import { combineReducers } from 'redux';const chatReducer = combineReducers({  chatLog,  statusMessage,  userName})​export default todoApp;

在实际的项目当中,你可以把reducer放在一个文件里面,然后统一的引入。

 import { combineReducers } from 'redux'import * as reducers from './reducers'const reducer = combineReducers(reducers)

工作流程


首先用户发出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();

上面是一个简单的计数器,唯一的作用就是把参数value的值,显示在网页上。Store 的监听函数设置为render,每次 State 的变化都会导致网页重新渲染。

下面加入一点变化,为Counter添加递增和递减的 Action。

 const Counter = ({ value, onIncrement, onDecrement }) => (  <div>  <h1>{value}</h1>  <button onClick={onIncrement}>+</button>  <button onClick={onDecrement}>-</button>  </div>);​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);