一腕铸、中間件的概念
如果要添加功能惜犀,只能在發(fā)送Action的時(shí)候才可以添加功能,即store.dispatch方法狠裹,所以舉一個(gè)官方的??要添加日志功能虽界,吧state和action都打印出來
let next = store.dispatch;
store.dispatch = function dispatchAndLog(action) {
console.log('dispatching', action);
next(action);
console.log('next state', store.getState());
}
以上就是對dispatch的改造,也就是中間件的雛形
因此中間件就是一個(gè)函數(shù)涛菠,對store.dispatch函數(shù)進(jìn)行改造莉御,在發(fā)出action和執(zhí)行reducer之間,添加其他功能
二俗冻、中間件的用法
中間件都是現(xiàn)成的礁叔,所以我們只要知道如何使用中間件就好
import { applyMiddleware, createStore } from 'redux';
import createLogger from 'redux-logger';
const logger = createLogger();
const store = createStore(
reducer,
applyMiddleware(logger)
);
上面舉了一個(gè)logger中間件的??,redux-logger提供一個(gè)生成器createLogger迄薄,用來生成日志中間件logger琅关,然后將它放在applyMiddleware方法中傳入createstore中
注意
(1)createStore方法可以接受整個(gè)應(yīng)用的初始狀態(tài)作為參數(shù),那樣的話讥蔽,applyMiddleware就是第三個(gè)參數(shù)了涣易。
const store = createStore(
reducer,
initial_state,
applyMiddleware(logger)
);
(2) applyMiddleware方法的三個(gè)參數(shù),就是三個(gè)中間件冶伞。有的中間件有次序要求新症,使用前要查一下文檔。比如碰缔,logger就一定要放在最后账劲,否則輸出結(jié)果會不正確。
const store = createStore(
reducer,
applyMiddleware(thunk, promise, logger)
);
三、redux-actions
createAction
原來創(chuàng)建action:const start = () => ({ type: 'START' })
現(xiàn)在創(chuàng)建action:import createAction from 'redux-actions'
const start = createAction('START')
handleActions
原來的寫法是需要switch或if來匹配
const todos = (state = defaultState, action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
id: action.id,
text: action.text,
str: action.str,
completed: false
}
]
case 'TOGGLE_TODO':
return state.map(todo =>
(todo.id === action.id)
? {...todo, completed: !todo.completed}
: todo
)
default:
return state
}
}
使用redux-actionsreducer操作state
:
const todos = handleActions({
ADD_TODO: (state, action) => ({...state,{
id: action.id,
text: action.text,
str: action.str,
completed: false
}}),
TOGGLE_TODO: (state, action) => state.map(todo =>
(todo.id === action.id)
? {...todo, completed: !todo.completed}
: todo
)
}, defaultState)
四瀑焦、異步處理action
官網(wǎng)一個(gè)??
import fetch from 'cross-fetch'
export const REQUEST_POSTS = 'REQUEST_POSTS'
function requestPosts(subreddit) {
return {
type: REQUEST_POSTS,
subreddit
}
}
export const RECEIVE_POSTS = 'RECEIVE_POSTS'
function receivePosts(subreddit, json) {
return {
type: RECEIVE_POSTS,
subreddit,
posts: json.data.children.map(child => child.data),
receivedAt: Date.now()
}
}
export const INVALIDATE_SUBREDDIT = ‘INVALIDATE_SUBREDDIT’
export function invalidateSubreddit(subreddit) {
return {
type: INVALIDATE_SUBREDDIT,
subreddit
}
}
// 來看一下我們寫的第一個(gè) thunk action 創(chuàng)建函數(shù)腌且!
// 雖然內(nèi)部操作不同,你可以像其它 action 創(chuàng)建函數(shù) 一樣使用它:
// store.dispatch(fetchPosts('reactjs'))
export function fetchPosts(subreddit) {
// Thunk middleware 知道如何處理函數(shù)榛瓮。
// 這里把 dispatch 方法通過參數(shù)的形式傳給函數(shù)铺董,
// 以此來讓它自己也能 dispatch action。
return function (dispatch) {
// 首次 dispatch:更新應(yīng)用的 state 來通知
// API 請求發(fā)起了禀晓。
dispatch(requestPosts(subreddit))
// thunk middleware 調(diào)用的函數(shù)可以有返回值精续,
// 它會被當(dāng)作 dispatch 方法的返回值傳遞。
// 這個(gè)案例中粹懒,我們返回一個(gè)等待處理的 promise重付。
// 這并不是 redux middleware 所必須的,但這對于我們而言很方便凫乖。
return fetch(`http://www.subreddit.com/r/${subreddit}.json`)
.then(
response => response.json(),
// 不要使用 catch确垫,因?yàn)闀东@
// 在 dispatch 和渲染中出現(xiàn)的任何錯(cuò)誤,
// 導(dǎo)致 'Unexpected batch number' 錯(cuò)誤帽芽。
// https://github.com/facebook/react/issues/6895
error => console.log('An error occurred.', error)
)
.then(json =>
// 可以多次 dispatch删掀!
// 這里,使用 API 請求結(jié)果來更新應(yīng)用的 state导街。
dispatch(receivePosts(subreddit, json))
)
}
}
四披泪、redux-promise中間件
import { createStore, applyMiddleware } from 'redux';
import promiseMiddleware from 'redux-promise';
import reducer from './reducers';
const store = createStore(
reducer,
applyMiddleware(promiseMiddleware)
);
這個(gè)中間件使得接受一個(gè)promise對象作為參數(shù),這時(shí)搬瑰,Action Creator 有兩種寫法款票。寫法一,返回值是一個(gè) Promise 對象跌捆。
######寫法一
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()
});
});
######寫法二:**action對象的payload屬性是一個(gè)promise對象**徽职,這需要從redux-actions模塊引入createAction方法
import { createAction } from 'redux-actions';
class AsyncApp extends Component {
componentDidMount() {
const { dispatch, selectedPost } = this.props
// 發(fā)出同步 Action
dispatch(requestPosts(selectedPost));
// 發(fā)出異步 Action
dispatch(createAction(
'FETCH_POSTS',
fetch(/some/API/${postTitle}.json
)
.then(response => response.json())
));
}
dispatch方法發(fā)出的是異步action,只有等到異步操作結(jié)束佩厚,這個(gè)action才會實(shí)際發(fā)出,createAction的第二個(gè)參數(shù)必須是一個(gè)promise對象