(一) react-router-redux中間件
所需環(huán)境:
(1) 用creact-react-app腳手架啟一個new項目
create-react-app new
(2)安裝redux
cnpm install redux --save-dev
(3)安裝react-redux
cnpm install react-redux --save-dev
(4)安裝redux-devtools
cnpm install redux-devtools --save-dev
(5)安裝react-router-dom
cnpm install react-router-dom --save-dev
(1) 安裝react-router-redux
react-router-redux作用:可以把router中的location(url信息等)注入到redux中脓匿,用redux來統(tǒng)一管理
cnpm install react-router-redux@next --save-dev
一般會用到react-router-redux中的:
ConnectedRouter , routerReducer , routerMiddleware , push
// 這里要注意毛俏,ConnectedRouter的首字母要大寫
// 注意是安裝( @next版本 )
// 在兩個地方會用到react-router-redux
1. 在store.js 用到routerReducer,routerMiddleware
2. 在index.js 用到ConnectedRouter
(2) 安裝 history 庫
history是一個JavaScript庫,可讓您輕松管理任何運行JavaScript的會話歷史記錄未蝌。用來管理歷史堆棧蔽午,導航易茬,確認導航以及在會話之間保持狀態(tài)。
cnpm install history --save-dev
(2) 新建 history.js
import createHistory from 'history/createBrowserHistory';
export default createHistory();
history.js在兩個地方會用到:
1.store.js 中
2.入口文件js中 (index.js)
(3) store.js
import {createStore, combineReducers, applyMiddleware} from 'redux';
import { routerReducer, routerMiddleware} from 'react-router-redux';
import username from '../component/username/reducer';
import history from '../history/history'; // 上面的history.js
import thunkMiddleware from 'redux-thunk'; // redux-thunk中間件用于dispatch一個函數(shù)
const totalReducer = {
username:username,
router:routerReducer // routerReducer
}
export const store = createStore( // 根據(jù)規(guī)則建立store
combineReducers({ // combineReducers組合多個reducer
...totalReducer
}),
window.devToolsExtension ? window.devToolsExtension() : undefined, // devTools插件
applyMiddleware(thunkMiddleware,routerMiddleware(history)) // routerMiddleware
);
export function injectAsyncReducer(name, reducer) { // 異步注入reducer
store.AsyncReducers = store.AsyncReducers || {};
if (store.AsyncReducers[name]) {
return ;
}
store.AsyncReducers[name] = reducer;
store.replaceReducer(combineReducers({ // store的api中的replaceReducer(nextReducer)方法
...totalReducer,
... store.AsyncReducers
}))
}
(4) index.js入口文件
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import {Provider} from 'react-redux'; //Provider的作用是保存store給子組件中的connect使用
import RouterA from './router/router';
// import {BrowserRouter} from 'react-router-dom';
import {ConnectedRouter} from 'react-router-redux'; // 引入ConnectedRouter
import history from './history/history';
import {store} from './store/store';
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}> // 使用ConnectedRouter
<App>
<RouterA/> // 路由組件及老,在App中用{this.props.children}引入
</App>
</ConnectedRouter>
</Provider>
, document.getElementById('root'));
registerServiceWorker();
(二) injectAsyncReducer函數(shù) (名字是自己定義的)
作用: 實時更新的reducer
(1) replaceReducer(nextReducer)
replaceReducer(nextReducer)是redux的api中的 store 的一個函數(shù)
- 作用:替換 store 當前用來計算 state 的 reducer抽莱。
這是一個高級 API。只有在你需要實現(xiàn)代碼分隔骄恶,而且需要立即加載一些 reducer 的時候才可能會用到它食铐。在實現(xiàn) Redux 熱加載機制的時候也可能會用到。 - ( 我的理解是: 實時更新的reducer )
- (redux中文文檔)http://www.redux.org.cn/docs/api/Store.html#replaceReducer
(2) injectAsyncReducer函數(shù)定義
store.js中
export function injectAsyncReducer(name, reducer) { // name, reducer作為參數(shù)
store.AsyncReducers = store.AsyncReducers || {}; // 存在賦值僧鲁,不存在賦值空對象
if (store.AsyncReducers[name]) { // store中的AsyncReducers對象存在name屬性虐呻,就返回
return ;
}
store.AsyncReducers[name] = reducer; // 不存在name屬性,就賦值給name屬性
store.replaceReducer(combineReducers({ // 用replaceReducer函數(shù)獲得時時更新的reducer
...totalReducer,
... store.AsyncReducers // 拿到AsyncReducers對象寞秃,給combineReducers
}))
}
(2) injectAsyncReducer函數(shù)使用
container.js中
import React,{Component} from 'react';
import Username from './username';
import {bindActionCreators} from 'redux';
import * as actionTotal from './action';
import {connect} from 'react-redux';
import {injectAsyncReducer} from '../../store/store'; // 引入
injectAsyncReducer('address',require('./reducer').default); // 使用
class usernameContainer extends Component {
render() {
return (
<div>
<Username {...this.props}></Username>
</div>
)
}
}
function mapStateToProps(state) {
return {
name: state.username.username
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(actionTotal,dispatch)
}
export default connect(mapStateToProps,mapDispatchToProps)(usernameContainer)
(三) redux-thunk中間件
作用: dispatch一個函數(shù)
- redux-thunk 支持 dispatch function斟叼,以此讓 action creator 控制反轉(zhuǎn)。被 dispatch 的 function 會接收 dispatch 作為參數(shù)春寿,并且可以異步調(diào)用它朗涩。這類的 function 就稱為 thunk。
(1) 安裝
cnpm install redux-thunk --save-dev
(2) 引入
import {createStore, combineReducers, applyMiddleware} from 'redux';
import username from '../component/username/reducer';
import { routerReducer, routerMiddleware} from 'react-router-redux';
import history from '../history/history';
import thunkMiddleware from 'redux-thunk'; // 引入
const totalReducer = {
username:username,
router:routerReducer
}
export const store = createStore(
combineReducers({
...totalReducer
}),
window.devToolsExtension ? window.devToolsExtension() : undefined,
applyMiddleware(thunkMiddleware,routerMiddleware(history)) // 使用
);
(3) 使用
action.js
export function getImage() {
return dispatch => { // return 一個函數(shù)绑改,dispatch函數(shù)作為參數(shù)
const p = fetch('http://image.baidu.com/channel/listjson?pn=0&rn=30&tag1=%E7%BE%8E%E5%A5%B3&tag2=%E5%85%A8%E9%83%A8&ie=utf8',{
method:'GET'
}).then(result => result.json() );
p.then(result => {
console.log(result,'result');
dispatch({ // dispatch一個action
type: actionTypes.GET_IMAGE,
payload: result
})
})
return p;
}
}
------------------------------------------------------------------------------------
reducer.js
import actionTypes from './constant';
const initialState = {
username:{
username: '重慶'
},
image:{}
}
export default function reducerA(state=initialState,action) {
switch(action.type) {
case actionTypes.GET_IMAGE:
return {
...state,
image:action.payload
}
default:
return state;
}
}
------------------------------------------------------------------------------------
container.js
import React,{Component} from 'react';
import Username from './username';
import {bindActionCreators} from 'redux';
import * as actionTotal from './action';
import {connect} from 'react-redux';
import {injectAsyncReducer} from '../../store/store';
injectAsyncReducer('address',require('./reducer').default);
class usernameContainer extends Component {
render() {
return (
<div>
<Username {...this.props}></Username>
</div>
)
}
}
function mapStateToProps(state) {
return {
name: state.username.username,
imageUrl:state.address.image.dat
// 拿到state.address.image.data命名為imageUrl谢床,傳給username.js
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(actionTotal,dispatch)
}
export default connect(mapStateToProps,mapDispatchToProps)(usernameContainer)
------------------------------------------------------------------------------------
username.js
import React,{Component} from 'react';
export default class username extends Component {
getI = () => {
this.props.getImage();
}
goG = (item,key) => {
return (
<div key={key}>
<img src={item.image_url} alt=""/>
</div>
)
}
render() {
// console.log(this.props.imageUrl,'this.props.imageUrl');
return (
<div>
主頁
<div onClick={this.getI}>
點擊獲得圖片
</div>
<br/>
<br/>
{
this.props.imageUrl && this.props.imageUrl.map(this.goG)
}
</div>
)
}
}
參考文檔:
(1) react-router-redux
https://github.com/ReactTraining/react-router/tree/master/packages/react-router-redux
(2)react-router v4 使用 history 控制路由跳轉(zhuǎn)
https://segmentfault.com/a/1190000011137828
(3) redux-thunk
https://github.com/gaearon/redux-thunk