项目地址
https://github.com/HeskeyBaoz...
项目预览
登录流
models/app
负责全局的登录状态管理。
在路由控制中,使用react-router
的onEnter
钩子保证在进入需要授权的页面中登录状态是保持的。
function requireAuth(nextState, replace, callback) {
app._store.dispatch({
type: 'app/enterAuth',
payload: {},
onComplete: callback // enter the component
});
}
function* enterAuth({payload, onComplete}, {put, take}) {
yield [put({type: 'checkToken'}), put({type: 'queryUser'})];
yield [take('app/hasToken'), take('app/queryUserSuccess')]; // promise the logged state
onComplete();
}
总体思想
所有的组件都尽量是stateless
, 所有的状态connect
组件一般都是路由组件。所有的分发dispatch
都交给了路由组件来完成。
这样我可以保证我可以复用一些Dumb
组件,比如PostsListBody
这个组件,既可以在文章列表页面使用,也可以在用户页面查看自己的文章列表使用。
数据的获取
有两种方式。
一种是dva.js
官方推荐的, 使用在models/posts
"订阅"数据源。这封装了react-redux-router增强的history
。
这样可以监听路由的变化,比如说下面在进入/posts
时,会发起一个获取文章列表的action
.
app.model({
subscriptions: {
setup: function ({history, dispatch}) {
history.listen(location => {
if (pathToRegExp('/posts').exec(location.pathname)) {
dispatch({
type: 'fetchPostsList',
payload: {pageInfo: {limit: 5, page: 1}}
});
}
});
}
}
});
还有一种是进入一些页面时,要保证一些数据已经在state
中了。这时我还是使用了react-router
的onEnter
钩子。
比如说在进入文章详细页面时,需要知道文章的基本元信息,标题作者等等。等到元信息加载完,再进入页面。
语法层面上上,多亏了有saga
的各种effects
创建器。可以很爽地写出各种异步代码
function requirePostPrepared(nextState, replace, callback) {
app._store.dispatch({
type: 'post_detail/initializePostDetail',
payload: {post_id: nextState.params.post_id},
onComplete: callback
});
}
function* initializePostDetail({payload, onComplete}, {put, call}) {
yield put({type: 'clear'});
const {post_id} = payload;
const {data} = yield call(fetchPostInfo, {post_id});
if (data) {
yield put({
type: 'saveInitialPostDetailInfo',
payload: {postInfo: data}
});
onComplete(); // enter the component
// then fetch the data
yield [
put({type: 'fetchPostContent'}),
put({type: 'fetchPostComments'})
];
}
}
文章列表
使用normalizr
将获取到的文章数组扁平化,方便后续修改visible
可见状态等。
原理如图:
这样在获取数据源展示数据时,即可使用一条语句
const dataSource = postsList.map(post_id => postsById[post_id]).filter(post => post);