前言
最近用create-react-app做了个一个门户网站,但对SEO不友好,只能用Nextjs重新搞。SPA和SSR的区别真的很大,有些什么不用调整就可以实现同构SSR方案,听一下就算了,在CMS面前没法落地的。研究了一段时间,发现在Nextjs下面没有合适的状态管理方案,Redux 可以管理一个页面的状态,但跨页面呢,SPA下没有跨页面的情况,但SSR下面每个页面都会分开从server下载,原本的方式不能适应了。
思路
- SPA
状态数据存储于Javascript的runtime之中,所谓页面跳转只是修改了浏览器的URL并呈现相应页面的内容,实质上还是那个页面和runtime,页面状态因此一直得以保存。 - SSR
将状态数据保存在cookie之中,因为来自CMS的显示数据已经被pre-render到页面中,这时的状态数据已经不多了,一般是用户的form data,token,selection,profile等。
简单实现
先安装react-cookies
npm install react-cookies
创建一个hook,
// hooks/cookieEntry.js
import { useState, useEffect } from "react"
import cookie from 'react-cookies';
export const useCookieEntry = (name, initVal) => {
const [content, setContent] = useState(initVal);
const value = cookie.load(name);
useEffect(() => {
if (value) {
setContent(value);
} else {
cookie.save(name, initVal);
}
}, [value]);
const updateContent = (value) => {
setContent(value);
cookie.save(name, value);
}
return [content, updateContent]
}
这里对React Hook做了一个包装,输入cookie的名称和初始值作为参数,初始化时除了会使用初始值外还会参考cookie里面的值,当setContent时会将content也放入cookie。
使用举例
创建React的组件
import { useCookieEntry } from "../hooks/cookieEntry";
export default () => {
const [{ score }, setScoreObj] = useCookieEntry('scoreObj', { score: 0 })
const onIncrease = e => {
setScoreObj({ score: score + 1 });
}
const onDecrease = e => {
setScoreObj({ score: score - 1 });
}
return (
<div>
<h3>Page A <br /> Score {score}</h3>
<div>
<button onClick={onIncrease}>increase</button>
<button onClick={onDecrease}>decrease</button>
</div>
</div>
)
}
只要使用相同的cookie名称就可以访问同一个cookie,因为cookie最终string存放数据,所以状态值的类型建议为string,Object,或者Array,否则容易发生序列化的问题。
注意事项
- 存放数据要适量,cookie不适合存放大量数据,以免影响性能。
- 这里的cookieEntry只是一个cookie,可以再用hook进行包装,用于存储一个form的内容,并加入validation,submission等function。
- 只要关闭浏览器cookie的内容就会消失。可以设置cookie的失效时间,实现登录状态保存一段时间的效果,还可以定制cookie的domain,path等。
最后
这只是一个初步的方案,我会在实践中不断完善,之后再做个pakcage放出来。