異步Action
一般情況下,每個(gè) API 請(qǐng)求都需要 dispatch 至少三種 action:
- 一種通知 reducer 請(qǐng)求開始的 action
對(duì)于這種 action,reducer 可能會(huì)切換一下 state 中的 isFetching 標(biāo)記。以此來告訴 UI 來顯示加載界面 - 一種通知 reducer 請(qǐng)求成功的 action
對(duì)于這種 action,reducer 可能會(huì)把接收到的新數(shù)據(jù)合并到 state 中,并重置 isFetching。UI 則會(huì)隱藏加載界面,并顯示接收到的數(shù)據(jù)。 - 一種通知 reducer 請(qǐng)求失敗的 action
對(duì)于這種 action,reducer 可能會(huì)重置 isFetching。另外,有些 reducer 會(huì)保存這些失敗信息,并在 UI 里顯示出來
{ type: 'FETCH_POSTS_REQUEST' }
{ type: 'FETCH_POSTS_FAILURE', error: 'Oops' }
{ type: 'FETCH_POSTS_SUCCESS', response: { ... } }
異步action 創(chuàng)建函數(shù)
// 第一個(gè)thunk action 創(chuàng)建函數(shù)
import fetch form 'cross-fetch'
export function fetchPosts(val){
return function(dispatch){
// 首次dispatch,Api 請(qǐng)求發(fā)起了
//通知 reducer 請(qǐng)求開始的 action
dispatch(requestPosts(val))
// thunk middleware 調(diào)用的函數(shù)可以有返回值
// 返回一個(gè)promise對(duì)象
return fetch(`htttp: www.sdfusd.com/${val}`)
.then(
response=>response.json(),
// 不要使用catch捕獲錯(cuò)誤
error=>console.log(error)
).then(json=>{
// 通知 reducer 請(qǐng)求成功的 action
dispatch(receivePosts(val,json))
})
}
}
使用 applyMiddleware()
import thunkMiddleware from 'redux-thunk'
import { createLogger } from 'redux-logger'
import { createStore, applyMiddleware } from 'redux'
const loggerMiddleware = createLogger()
const store = createStore(
rootReducer,
applyMiddleware(
thunkMiddleware, // 允許我們dispatch函數(shù)
loggerMiddleware
)
)
//調(diào)用
store.dispatch(fetchPosts('reactjs')).then(()=>console.log(store.getState()))
// 使用async函數(shù)優(yōu)雅實(shí)現(xiàn)
export const getProData=()=>{
// 返回異步dispatch action創(chuàng)建函數(shù)
return async dispatch=>{
try{
let result = await API.getProduction()
dispatch({
type: GETPROGEUDF,
data: result
})
}catch(err){
console.log(err)
}
}
}
// 頁面調(diào)用
import { getProData } from ''./actions'
this.props.getProData()
Middleware
middleware是位于action被發(fā)起之后,到達(dá)reducer之前的擴(kuò)展點(diǎn),可以用來進(jìn)行日志記錄,創(chuàng)建崩潰報(bào)告、調(diào)用異步接口等等
Middleware 接收了一個(gè) next() 的 dispatch 函數(shù),并返回一個(gè) dispatch 函數(shù),返回的函數(shù)會(huì)被作為下一個(gè) middleware 的 next()
搭配React Router
const Root = ({ store })=>(
<Provider store={store}>
<Router>
<Route path="/" component={App} />
</Router>
</Provider>
)
技巧
使用對(duì)象展開符 ...spread 替代 Object.assign()
reducer 里不要使用 Object.assign(state, newData),應(yīng)該使用 Object.assign({}, state, newData)
服務(wù)端渲染
當(dāng)服務(wù)器收到請(qǐng)求時(shí),將組件渲染成HTML字符串,返回給客戶端
使用React.renderToString()
import { renderToString } from 'react-dom/server'
function handleRender(req, res) {
// 創(chuàng)建新的 Redux store 實(shí)例
const store = createStore(counterApp);
// 把組件渲染成字符串
const html = renderToString(
<Provider store={store}>
<App />
</Provider>
)
// 從 store 中獲得初始 state
const preloadedState = store.getState();
// 把渲染后的頁面內(nèi)容發(fā)送給客戶端
res.send(renderFullPage(html, preloadedState));
}
function renderFullPage(html, preloadedState){
return `
<!doctype html>
<html>
<head>
<title>Redux Universal Example</title>
</head>
<body>
<div id="root">${html}</div>
<script>
// window.__INITIAL_STATE__ 獲取 preloadedState
window.__INITIAL_STATE__ = ${JSON.stringify(preloadedState)}
</script>
<script src="/static/bundle.js"></script>
</body>
</html>
`
}
API文檔
Redux
- createStore(reducer,[preloaderdState, [enhancer]])
- combineReducers(reducers)
- applyMiddleware(...middlewares)
-bindActionCreatores(actionCreators, dispatch) - compose(...functions)
store API
- getState()
- dispatch
- subscribe(listener)
- getReducer()
- replaceReducer(nextReducer)
React Redux API
- <Provider store={store}>
- connect()