React-Redux 使用 Fetch 进行网络请求

本篇主要记录在 React-Redux 中使用中间件用 fetch 进行网络请求,在 请求开始请求结束 时,中间件自动发送相应的 action 然后更新应用页面。

由于 fetch 并没有正式发布,而且在浏览器中支持也不是很好,所以使用 isomorphic-fetch 来进行 fetch 操作。

示例1

主要功能:使用 fetch 请求服务器获取数据,请求开始 和 请求结束(失败/成功)分别分发 action 刷新页面状态,并且显示请求结果。

step1: 定义 state 结构

1
2
3
4
5
6
7
8
state = {
isFetching: false,
isSuccess: false,
data: {
id: 0,
msg: ""
}
}

state 定义成如上,isFetching 表示是否正在进行网络请求,data 则表示获取到的请求结果。

step2: 定义 action

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import fetch from 'isomorphic-fetch';
export const FETCH_BEGIN = "FETCH_BEGIN";
export const FETCH_OVER = "FETCH_OVER";
const fetchBegin = (url) => ({
type: FETCH_BEGIN,
url
});
// status,data 分别表示请求是否成功和请求结果
const fetchEnd = (url, status, data) => ({
type: FETCH_OVER,
url,
status,
data
});
export const fetchAction = function (url) {
return function (dispatch) {
dispatch(fetchBegin(url)); // 请求开始
return fetch(url)
.then(response => {
return response.json()
})
.then(json => {
dispatch(fetchEnd(url, true, json)) // 请求结束(成功)
})
.catch(e=> {
dispatch(fetchEnd(url, false, {})) // 请求结束(异常)
});
};
};

上面定义了两种 Object 类型的 action,分别是 fetchBegin()fetchEnd() ,分别表示请求开始和请求结束,其中请求结束时 action 携带了请求状态、请求结果。但是这两种 action 都不会由 store 直接分发,而是在请求开始、请求结束时由中间件替我们分发相应的 action

发起一个请求直接使用 fetchAction,在这个函数里面会自动分发请求开始的 action,在请求结束之后,也会自动分发请求结束的 action

step3: 定义 reducer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import {combineReducers} from 'redux';
function fetchStatus(state = false, action) {
switch (action.type) {
case 'FETCH_BEGIN':
return true;
case 'FETCH_OVER':
return false;
break;
default:
return state;
}
}
function fetchData(state = {}, action) {
switch (action.type) {
case 'FETCH_OVER':
return action.data;
break;
default:
return state;
}
}
function fetchResultStatus(state = true, action) {
switch (action.type) {
case 'FETCH_OVER':
return action.status;
break;
default:
return state;
}
}
var reducer = combineReducers({
isFetching: fetchStatus,
isSuccess: fetchResultStatus,
data: fetchData
});

定义处理 state 的函数 reducer

step4: 定义组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import React from "react";
import {combineReducers} from 'redux';
import {connect} from 'react-redux';
import {fetchAction} from "./actions.js";
const mapStateToProps = (state, ownProps) => ({
isFetching: state.isFetching,
isSuccess: state.isSuccess,
msg: state.data.msg
});
const mapDispatchToProps = (dispatch, ownProps) => ({
fetchAction: ()=> {
dispatch(fetchAction("http://127.0.0.1:3000"));
}
});
const App = React.createClass({
componentDidMount: function () {
this.props.fetchAction();
},
render: function () {
return <div>
<h2>isLoading:</h2>
<div>{this.props.isFetching + ""}</div>
<h2>isSuccess:</h2>
<div>{this.props.isSuccess + ""}</div>
<h2>msg:</h2>
<div>{this.props.msg}</div>
<br />
</div>
}
});
const ContainerApp = connect(
mapStateToProps,
mapDispatchToProps
)(App);
export default ContainerApp;

使用 connect()reduxstatedispatch() 分发action的行为转换给 App 组件的 props 属性。
App 一旦被加载的时候,就调用 fetchAction 进行网络请求获取数据。

step5: 使用 React-Redux 和 中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from "react";
import ReactDOM from "react-dom";
import {createStore, combineReducers, applyMiddleware} from "redux";
import {Provider} from 'react-redux';
import thunkMiddleware from "redux-thunk";
import createLogger from 'redux-logger';
import ContainerApp from './ContainerApp.js';
import reducer from './reducer.js';
const logger = createLogger();
var store = createStore(reducer, applyMiddleware(thunkMiddleware, logger));
ReactDOM.render(
<Provider store={store}>
<ContainerApp />
</Provider>,
document.getElementById("root"));