一、中间件的概念
如果要添加功能,只能在发送Action的时候才可以添加功能,即store.dispatch方法,所以举一个官方的🌰要添加日志功能,吧state和action都打印出来
let next = store.dispatch;
store.dispatch = function dispatchAndLog(action) {
console.log('dispatching', action);
next(action);
console.log('next state', store.getState());
}
以上就是对dispatch的改造,也就是中间件的雏形
因此中间件就是一个函数,对store.dispatch函数进行改造,在发出action和执行reducer之间,添加其他功能
二、中间件的用法
中间件都是现成的,所以我们只要知道如何使用中间件就好
import { applyMiddleware, createStore } from 'redux';
import createLogger from 'redux-logger';
const logger = createLogger();
const store = createStore(
reducer,
applyMiddleware(logger)
);
上面举了一个logger中间件的🌰,redux-logger提供一个生成器createLogger,用来生成日志中间件logger,然后将它放在applyMiddleware方法中传入createstore中
注意
(1)createStore方法可以接受整个应用的初始状态作为参数,那样的话,applyMiddleware就是第三个参数了。
const store = createStore(
reducer,
initial_state,
applyMiddleware(logger)
);
(2) applyMiddleware方法的三个参数,就是三个中间件。有的中间件有次序要求,使用前要查一下文档。比如,logger就一定要放在最后,否则输出结果会不正确。
const store = createStore(
reducer,
applyMiddleware(thunk, promise, logger)
);
三、redux-actions
createAction
原来创建action:const start = () => ({ type: 'START' })
现在创建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
官网一个🌰
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
}
}
// 来看一下我们写的第一个 thunk action 创建函数!
// 虽然内部操作不同,你可以像其它 action 创建函数 一样使用它:
// store.dispatch(fetchPosts('reactjs'))
export function fetchPosts(subreddit) {
// Thunk middleware 知道如何处理函数。
// 这里把 dispatch 方法通过参数的形式传给函数,
// 以此来让它自己也能 dispatch action。
return function (dispatch) {
// 首次 dispatch:更新应用的 state 来通知
// API 请求发起了。
dispatch(requestPosts(subreddit))
// thunk middleware 调用的函数可以有返回值,
// 它会被当作 dispatch 方法的返回值传递。
// 这个案例中,我们返回一个等待处理的 promise。
// 这并不是 redux middleware 所必须的,但这对于我们而言很方便。
return fetch(`http://www.subreddit.com/r/${subreddit}.json`)
.then(
response => response.json(),
// 不要使用 catch,因为会捕获
// 在 dispatch 和渲染中出现的任何错误,
// 导致 'Unexpected batch number' 错误。
// https://github.com/facebook/react/issues/6895
error => console.log('An error occurred.', error)
)
.then(json =>
// 可以多次 dispatch!
// 这里,使用 API 请求结果来更新应用的 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)
);
这个中间件使得接受一个promise对象作为参数,这时,Action Creator 有两种写法。写法一,返回值是一个 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属性是一个promise对象**,这需要从redux-actions模块引入createAction方法
import { createAction } from 'redux-actions';
class AsyncApp extends Component {
componentDidMount() {
const { dispatch, selectedPost } = this.props
// 发出同步 Action
dispatch(requestPosts(selectedPost));
// 发出异步 Action
dispatch(createAction(
'FETCH_POSTS',
fetch(/some/API/${postTitle}.json
)
.then(response => response.json())
));
}
dispatch方法发出的是异步action,只有等到异步操作结束,这个action才会实际发出,createAction的第二个参数必须是一个promise对象
网友评论