以下代码来源于我的项目NovelAPP:https://github.com/SemperChen/NovelAPP
首先是从this.props.dispatch发起网络请求,如MainDetail(BookDetailPage的子组件)
js/commons/MainDetail.js
下面是请求书籍详情, bookDetailUrl是请求书籍详情网址
componentDidMount() {
...
this.props.dispatch(requestDetail(this.bookDetailUrl))
...
}
js/actions/detail.js
...
export function requestDetail(bookDetailUrl) {
return {
type: REQUEST_DETAIL,
bookDetailUrl
};
}
...
我们从上面代码可以看出,其实
requestDetail(this.bookDetailUrl)
这个方法返回的就是以下这个action对象
{
type: REQUEST_DETAIL,
bookDetailUrl
}
即代码
this.props.dispatch(requestDetail(this.bookDetailUrl))
可以看成
this.props.dispatch({
type: REQUEST_DETAIL,
bookDetailUrl
})
当dispatch把action即{ type: REQUEST_DETAIL, bookDetailUrl } 发出去之后,redux收到这个action请求,会执行以下代码中的detail(state=initalState, action)方法
js/reducers/detail.js
export default function detail(state = initialState, action) {
switch (action.type) {
case REQUEST_DETAIL:
return {
...state,
isFetchingDetail:true
};
...
}
}
并返回以下对象
{
...state,
isFetchingDetail:true
};
然后会执行以下代码中mapStateToProps这个方法 ,将isFetchingDetail=true传进来
js/commons/MainDetail.js
function mapStateToProps(state) {
const {bookDetail, isFetchingDetail} = state.detail;
const {items: bookmarks} = state.bookmarks;
return {bookDetail, bookmarks, isFetchingDetail}
}
上面mapStateToProps方法执行后,会重新渲染render等方法
render() {
...
return (
{this.props.isFetchingDetail
?
加载中,
请稍等
: null
}
...
)
}
这时,因为上面代码中this.props.isFetchingDetail=true,加载中,请稍等 这几个字便出现,如图
与此同时saga也收到REQUEST_DETAIL请求
js/sagas/index.js
const rootSaga = function* root() {
yield all([
...
takeLatestFetch(REQUEST_DETAIL,fetchBookDetail),
...
])
};
export default rootSaga;
以上takeLatestFetch(REQUEST_DETAIL, fetchBookDetail),这个方法监听到REQUEST_DETAIL请求后,就会执行fetchBookDetail 这个方法,并将action即{ type: REQUEST_DETAIL, bookDetailUrl }中bookDetailUrl作为参数
js/sagas/detail.js
export function* fetchBookDetail(params) {
try {
const {bookDetailUrl} = params;
const bookDetail = yield call(fetchJSON, bookDetailUrl);
yield put(receiveDetail(bookDetail))
} catch (e) {
console.log('detail fetchBookDetail:', e.message);
}
};
const bookDetail = yield call(fetchJSON, bookDetailUrl);
执行到上面这一步的时候,会把bookDetailUrl网址作为fetchJSON方法的参数,发起网络请求,并将请求结果返回,即bookDetail
js/utils/HttpUtil
export function fetchJSON(url) {
return new Promise((resolve, reject) => {
fetch(url, {
headers: {
'Content-Type': 'application/json',
'Accept-Charset': 'utf-8',
'User-Agent': 'Mozilla/5.0 (Linux; X11)',
}
})
.then((response) => {
return response.json()
})
.catch((error) => {
reject(error);
}).then((responseData) => {
if (!responseData) {
reject(new Error('fetchJSON:responseData is null'));
return;
}
resolve(responseData);
}).done();
})
}
yield put(receiveDetail(bookDetail))
执行到这一步时候,saga会将网络请求返回的结果bookDetail发出去,类似于刚开始介绍的this.props.dispatch
js/actions/receiveDetail.js
export function receiveDetail(bookDetail) {
return {
type: RECEIVE_DETAIL,
bookDetail
};
}
因为receiveDetail(bookDetail) 返回的值是{ type: RECEIVE_DETAIL, bookDetail } ,所以yield put(receiveDetail(bookDetail))相当于
yield put({
type: RECEIVE_DETAIL,
bookDetail
})
或相当于
this.props.dispatch({
type: RECEIVE_DETAIL,
bookDetail
})
然后redux收到RECEIVE_DETAIL请求后,会执行以下方法,并将action:{type: RECEIVE_DETAIL, bookDetail}传到下面代码里,然后action.type跟case RECEIVE_DETAIL匹配,返回{ ...state, bookDetail: action.bookDetail, isFetchingDetail: false }
js/reducers/detail.js
export default function detail(state = initialState, action) {
switch (action.type) {
...
case RECEIVE_DETAIL:
return {
...state,
bookDetail: action.bookDetail,
isFetchingDetail:false
};
...
}
}
然后会将上面bookDetail和isFetchingDetail传到mapStateToProps
js/commons/MainDetail.js
function mapStateToProps(state) {
const {bookDetail, isFetchingDetail} = state.detail;
const {items: bookmarks} = state.bookmarks;
return {bookDetail, bookmarks, isFetchingDetail}
}
render将重新渲染,返回的bookDetail书籍详情将会显示
render(){
...
this.bookDetail = this.props.bookDetail;
return(
...
{this.bookDetail.bookName}
...
)
...
}
因为返回的 isFetchingDetail=false,下图中的加载中,请稍等将消失