redux學(xué)習(xí)

(1) redux簡(jiǎn)介


reducer

reducer 是一個(gè)計(jì)劃函數(shù),接收舊的 state 和 action,生成新的 state

? ? ? ? ? ? combineReducers:多 reducer 合并成一個(gè) reducer

? ? ? ? ? ? state:狀態(tài)

? ? ? ? ? ? action:一個(gè)對(duì)象,必須包含 type 字段

store

存儲(chǔ)器,存儲(chǔ)所有的狀態(tài)和方法(state狀態(tài) ,subscribe訂閱方法,dispatch狀態(tài)修改方法)

? ? ? ? ? createStore:創(chuàng)建 store 對(duì)象,包含 getState, dispatch, subscribe等

? ? ? ? ? dispatch:觸發(fā) action,生成新的 state

? ? ? ? ? subscribe:實(shí)現(xiàn)訂閱功能,每次觸發(fā) dispatch 的時(shí)候,會(huì)執(zhí)行訂閱函數(shù)

view

視圖層,控制顯示

middleware

擴(kuò)展 dispatch 函數(shù),dispatch 函數(shù)中不同功能 的方法提取出來(lái)

(2) ?Redux 的工作流程


1)創(chuàng)建Store

import { createStore } from 'redux';

const defaultState = 0;

// Action 就是 View 發(fā)出的通知,表示 State 應(yīng)該要發(fā)生變化了。其中的type屬性是必須的,表示 Action 的名稱。其他屬性可以自由設(shè)置

const action = {

? type: 'ADD',

? payload: 2

};

// Reducer 是一個(gè)函數(shù),它接受 Action 和當(dāng)前 State 作為參數(shù),返回一個(gè)新的 State。Store 收到 Action 以后,必須給出一個(gè)新的 State,這樣 View 才會(huì)發(fā)生變化。

const reducer = (state = defaultState, action) => {

? switch (action.type) {

? ? case 'ADD':

? ? ? return state + action.payload;

? ? default:

? ? ? return state;

? }

};

// createStore接受 Reducer 作為參數(shù),生成一個(gè)新的 Store

const store = createStore(reducer);

2) 用戶發(fā)出 Action

// Action 是一個(gè)對(duì)象。其中的type屬性是必須的,表示 Action 的名稱。其他屬性可以自由設(shè)置

// View 要發(fā)送多少種消息,就會(huì)有多少種 Action。如果都手寫(xiě),會(huì)很麻煩??梢远x一個(gè)函數(shù)來(lái)生成 Action,這個(gè)函數(shù)就叫 Action Creator,如addTodo就是Action Creator

function addTodo(text) {

? return {

? ? type: 'ADD',

? ? text

? }

}

const action = addTodo(3);

// store.dispatch()是 View 發(fā)出 Action 的唯一方法,會(huì)觸發(fā) Reducer 的自動(dòng)執(zhí)行

store.dispatch(action);

3) Store 允許使用store.subscribe方法設(shè)置監(jiān)聽(tīng)函數(shù),一旦 State 發(fā)生變化,就自動(dòng)執(zhí)行這個(gè)函數(shù)。

//? listener可以通過(guò)store.getState()得到當(dāng)前狀態(tài)。只要把 View 的更新函數(shù)(對(duì)于 React 項(xiàng)目,就是組件的render方法或setState方法)放入listen,就會(huì)實(shí)現(xiàn) View 的自動(dòng)渲染。

function listerner() {

? let newState = store.getState();

? component.setState(newState);

}

store.subscribe(listener);

4) Redux 提供了一個(gè)combineReducers方法,用于 Reducer 的拆分。你只要定義各個(gè)子 Reducer 函數(shù),然后用這個(gè)方法,將它們合成一個(gè)大的 Reducer。

import { combineReducers } from 'redux';

const chatReducer = combineReducers({

? chatLog,

? statusMessage,

? userName

})

export default chatReducer;

或者可以把所有子 Reducer 放在一個(gè)文件里面,然后統(tǒng)一引入。

import { combineReducers } from 'redux'

i

import * as reducers from './reducers'

const reducer = combineReducers(reducers)

5) 中間件是一個(gè)函數(shù),對(duì)store.dispatch方法進(jìn)行了改造,在發(fā)出 Action 和執(zhí)行 Reducer 這兩步之間,添加了其他功能。

createStore方法可以接受整個(gè)應(yīng)用的初始狀態(tài)作為參數(shù),那樣的話,applyMiddleware就是第三個(gè)參數(shù)了。

// applyMiddlewares是 Redux 的原生方法,作用是將所有中間件組成一個(gè)數(shù)組,依次執(zhí)行。

const store = createStore(

? reducer,

? initial_state,

? applyMiddleware(thunk, promise, logger)

);

常用中間件:

redux-thunk 中間件

異步操作的第一種解決方案就是,寫(xiě)出一個(gè)返回函數(shù)的 Action Creator,然后使用redux-thunk中間件改造store.dispatch

import { createStore, applyMiddleware } from 'redux';

import thunk from 'redux-thunk';

import reducer from './reducers';

// 使用redux-thunk中間件,改造store.dispatch,使得后者可以接受函數(shù)作為參數(shù)。

const store = createStore(

? reducer,

? applyMiddleware(thunk)

);

// fetchPosts是一個(gè)Action Creator(動(dòng)作生成器),返回一個(gè)函數(shù)。這個(gè)函數(shù)執(zhí)行后,先發(fā)出一個(gè)Action(requestPosts(postTitle)),然后進(jìn)行異步操作。拿到結(jié)果后,先將結(jié)果轉(zhuǎn)成 JSON 格式,然后再發(fā)出一個(gè) Action(?receivePosts(postTitle, json))。

const fetchPosts = postTitle => (dispatch, getState) => {

? dispatch(requestPosts(postTitle));

? return fetch(`/some/API/${postTitle}.json`)

? ? .then(response => response.json())

? ? .then(json => dispatch(receivePosts(postTitle, json)));

? };

};

store.dispatch(fetchPosts('reactjs'));

redux-promise 中間件

另一種異步操作的解決方案,就是讓 Action Creator 返回一個(gè) Promise 對(duì)象。

import { createStore, applyMiddleware } from 'redux';

import promiseMiddleware from 'redux-promise';

import reducer from './reducers';

//promiseMiddleware中間件使得store.dispatch方法可以接受 Promise 對(duì)象作為參數(shù)。

const store = createStore(

? reducer,

? applyMiddleware(promiseMiddleware)

);

//Action Creator 有兩種寫(xiě)法。寫(xiě)法一,返回值是一個(gè) Promise 對(duì)象。

const fetchPosts =

? (dispatch, postTitle) => new Promise(function (resolve, reject) {

? ? dispatch(requestPosts(postTitle));

? ? return fetch(`/some/API/${postTitle}.json`)

? ? ? .then(response => {

? ? ? ? type: 'FETCH_POSTS',

? ? ? ? payload: response.json()

? ? ? });

});

//寫(xiě)法二, Action 對(duì)象的payload屬性是一個(gè) Promise 對(duì)象。這需要從redux-actions模塊引入createAction方法,并且寫(xiě)法也要變成下面這樣。

import { createAction } from 'redux-actions';

const fetchPosts = createAction(

? ? ? 'FETCH_POSTS',

? ? ? fetch(`/some/API/${postTitle}.json`)

? ? ? ? .then(response => response.json())

? ? )

(3) React-Redux

1)UI組件與容器組件

UI 組件負(fù)責(zé) UI 的呈現(xiàn),容器組件負(fù)責(zé)管理數(shù)據(jù)和邏輯。

UI 組件:

只負(fù)責(zé) UI 的呈現(xiàn),不帶有任何業(yè)務(wù)邏輯

沒(méi)有狀態(tài)(即不使用this.state這個(gè)變量)

所有數(shù)據(jù)都由參數(shù)(this.props)提供

不使用任何 Redux 的 API

容器組件:

負(fù)責(zé)管理數(shù)據(jù)和業(yè)務(wù)邏輯,不負(fù)責(zé) UI 的呈現(xiàn)

帶有內(nèi)部狀態(tài)

使用 Redux 的 API

React-Redux 規(guī)定,所有的 UI 組件都由用戶提供,容器組件則是由 React-Redux 自動(dòng)生成。

2)connect()

React-Redux 提供connect方法,用于從 UI 組件生成容器組件。connect的意思,就是將這兩種組件連起來(lái)。connect方法的完整 API 如下:

import { connect } from 'react-redux'

const VisibleTodoList = connect(

? mapStateToProps,

? mapDispatchToProps

)(TodoList)

上面代碼中,connect方法接受兩個(gè)參數(shù):mapStateToProps和mapDispatchToProps。它們定義了 UI 組件的業(yè)務(wù)邏輯。前者負(fù)責(zé)輸入邏輯,即將state映射到 UI 組件的參數(shù)(props),后者負(fù)責(zé)輸出邏輯,即將用戶對(duì) UI 組件的操作映射成 Action。

mapStateToProps()

mapStateToProps是一個(gè)函數(shù)。它的作用就是像它的名字那樣,建立一個(gè)從(外部的)state對(duì)象到(UI 組件的)props對(duì)象的映射關(guān)系。

// mapStateToProps是一個(gè)函數(shù),它接受state作為參數(shù),返回一個(gè)對(duì)象。這個(gè)對(duì)象有todos屬性和visibilityFilter屬性,代表 UI 組件的同名參數(shù)

const mapStateToProps = (state) => {

? return {

? ? todos: getVisibleTodos(state.todos, state.visibilityFilter)

? }

}

// mapStateToProps的第一個(gè)參數(shù)總是state對(duì)象,還可以使用第二個(gè)參數(shù),代表容器組件的props對(duì)象。

const mapStateToProps = (state, ownProps) => {

? return {

? ? active: ownProps.filter === state.visibilityFilter

? }

}

// getVisibleTodos從state算出?todos?的值

const getVisibleTodos = (todos, filter) => {

? switch (filter) {

? ? case 'SHOW_ALL':

? ? ? return todos

? ? case 'SHOW_COMPLETED':

? ? ? return todos.filter(t => t.completed)

? ? case 'SHOW_ACTIVE':

? ? ? return todos.filter(t => !t.completed)

? ? default:

? ? ? throw new Error('Unknown filter: ' + filter)

? }

}

mapDispatchToProps()

mapDispatchToProps是connect函數(shù)的第二個(gè)參數(shù),用來(lái)建立 UI 組件的參數(shù)到store.dispatch方法的映射。也就是說(shuō),它定義了哪些用戶的操作應(yīng)該當(dāng)作 Action,傳給 Store。它可以是一個(gè)函數(shù),也可以是一個(gè)對(duì)象。

// 如果mapDispatchToProps是一個(gè)函數(shù),會(huì)得到dispatch和ownProps(容器組件的props對(duì)象)兩個(gè)參數(shù)。mapDispatchToProps作為函數(shù),應(yīng)該返回一個(gè)對(duì)象,該對(duì)象的每個(gè)鍵值對(duì)都是一個(gè)映射,定義了 UI 組件的參數(shù)怎樣發(fā)出 Action。

const mapDispatchToProps = (

? dispatch,

? ownProps

) => {

? return {

? ? onClick: () => {

? ? ? dispatch({

? ? ? ? type: 'SET_VISIBILITY_FILTER',

? ? ? ? filter: ownProps.filter

? ? ? });

? ? }

? };

}

// 如果mapDispatchToProps是一個(gè)對(duì)象,它的每個(gè)鍵名也是對(duì)應(yīng) UI 組件的同名參數(shù),鍵值應(yīng)該是一個(gè)函數(shù),會(huì)被當(dāng)作 Action creator ,返回的 Action 會(huì)由 Redux 自動(dòng)發(fā)出。

const mapDispatchToProps = {

? onClick: (filter) => {

? ? type: 'SET_VISIBILITY_FILTER',

? ? filter: filter

? };

}

3)<Provider> 組件

React-Redux 提供Provider組件,可以讓容器組件拿到state。

import { Provider } from 'react-redux'

i

import { createStore } from 'redux'

i

import todoApp from './reducers'

i

import App from './components/App'

let store = createStore(todoApp);

// Provider在根組件外面包了一層,這樣一來(lái),App的所有子組件就默認(rèn)都可以拿到state了。

render(

? <Provider store={store}>

? ? <App />

? </Provider>,

? document.getElementById('root')

)

// store放在了上下文對(duì)象context上面。調(diào)用時(shí),子組件可以從context拿到store

class VisibleTodoList extends Component {

? componentDidMount() {

? ? const { store } = this.context;

? ? this.unsubscribe = store.subscribe(() =>

? ? ? this.forceUpdate()

? ? );

? }

? render() {

? ? const props = this.props;

? ? const { store } = this.context;

? ? const state = store.getState();

? ? // ...

? }

}

VisibleTodoList.contextTypes = {

? store: React.PropTypes.object

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • redux學(xué)習(xí)筆記 學(xué)習(xí)動(dòng)機(jī) 隨著 JavaScript 單頁(yè)應(yīng)用開(kāi)發(fā)日趨復(fù)雜,JavaScript 需要管理比任...
    flura閱讀 424評(píng)論 0 0
  • redux自述 Redux 是 JavaScript 狀態(tài)容器,提供可預(yù)測(cè)化的狀態(tài)管理。 (如果你需要一個(gè) Wor...
    WittyLu閱讀 429評(píng)論 0 0
  • 參考阮老師的文章 測(cè)試項(xiàng)目地址 Redux解決了哪些問(wèn)題?什么時(shí)候使用它? React 只是 DOM 的一個(gè)抽象層...
    tonytong閱讀 624評(píng)論 0 0
  • 設(shè)計(jì)思想 Redux的設(shè)計(jì)思想很簡(jiǎn)單,就兩句話: 1、Web應(yīng)用是一個(gè)狀態(tài)機(jī),視圖與狀態(tài)是一一對(duì)應(yīng)的;2、所有的狀...
    九又四分之三o閱讀 295評(píng)論 0 0
  • 一元旅游自露面以來(lái),頻頻受到各方質(zhì)疑,一方面是一元旅游本身如同天下掉下來(lái)的餡餅,這美好的餡餅背后又深藏陷阱,不僅涉...
    財(cái)神出位閱讀 667評(píng)論 0 0

友情鏈接更多精彩內(nèi)容