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);复制代码