目前绝大多数网站还是一个多页的结构,但其实一个网站已经完全可以做成一个spa,比如youtube就是一个spa,最近公司项目都是采用react+mobx服务端渲染的单页面应用的形式,踩了一些坑,有一些自己的体验,所以把项目抽了出来去掉了业务代码,留了一个架子分享一下。
目前react主流的状态管理使用的比较多的是redux,我司之前有个项目也是react+redux,从我个人使用下来的感受来说,对于绝大多数的前端应用场景,mobx远比redux更合适,更简单使用,更容易上手。
效果
登陆,注册
添加item到列表中
如果路由中没有的页面,处理404
如何使用
git clone git@github.com:L-x-C/isomorphic-react-with-mobx.git
cd isomorphic-react-with-mobx
npm install
Dev (客户端渲染)
npm start
open http://localhost:3000
Production (服务端渲染)
npm run server
open http://localhost:20000
一些经常会遇到的情况
如何在服务端获取数据?
在每个component中增加一个onEnter,用一个promise来处理,在这个promise中发起一个action,改变mobx中的states值
@action
static onEnter({states, pathname, query, params}) {
return Promise.all([
menuActions.setTDK(states, '列表'),
jobActions.fetchJobList(states, query)
]);
}
之所以能这么做,是因为在serverRender中有一个onEnter的预处理,会根据component的嵌套从最外层一直遍历到最里层的onEnter,并执行其中的的方法
import async from 'async';
export default (renderProps, states) => {
const params = renderProps.params;
const query = renderProps.location.query;
const pathname = renderProps.location.pathname;
let onEnterArr = renderProps.components.filter(c => c.onEnter);
return new Promise((resolve, reject) => {
async.eachOfSeries(onEnterArr, function(c, key, callback) {
let enterFn = c.onEnter({states, query, params, pathname});
if (enterFn) {
enterFn.then(res => {
if (res) {
//处理Promise回调执行,比如登陆
res.forEach((fn) => {
if (Object.prototype.toString.call(fn) === '[object Function]') {
fn();
}
});
}
if (key === (onEnterArr.length - 1)) {
resolve();
}
callback();
}).catch(err => {
reject(err);
});
} else {
callback();
}
});
});
};
如何在服务端设置tdk(title, description, keywords)?
这其实在上一个问题中就已经出现了,onEnter中有一个setTDK(states, t, d, k)的方法,使用他就可以设置tdk的值
如何在服务端进行跳转?
在浏览器环境中,我们可以设置window.location.href = url来进行跳转。
但是在服务器环境中,并没有window和document这2个对象,所以我们在服务器环境中抛出一个异常,然后捕获到之后进行302跳转。
具体可以看src/helpers/location.js
, 中的redirect
function
他会自动判断当前环境,来选择使用哪一种跳转
import {redirect} from './helpers/location';
@action
static onEnter({states, query, params}) {
redirect('http://www.xxx.com');
}
mobx的原理及使用就不在这里做详细的介绍了,网上搜一搜有很多。
我相信我们所采用的一些方法也许并不是最完美的解法,如果有更好的欢迎来github中提issue探讨交流,互相学习~项目地址在此
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。