# 正文
在之前的小节中我们已经完成了数据同构,如果用来进行实际项目开发的话也能满足,但是有些时候用起来不够舒服,因为还存在一些不足和一些可以优化的空间。
当然这也是可以理解的,我们之前的阶段是建造阶段,为的是满足需求而已,现在是装修优化阶段,所以是时候把这些瑕疵给干掉了。
到底有哪些地方需要优化呢?下面一步一步来看。
# 组件内 state 初始化存在重复逻辑
下面这段代码是list页面组件构造函数内的数据获取逻辑,通过__SERVER__这个全局变量来判断是否是服务端渲染还是客户端渲染,最后给到state初始值。
//...
constructor(props) {
super(props);
let initialData = null;//初始化数据
if(__SERVER__){
//如果是在服务端执行
initialData = props.staticContext.initialData||{};
}else{
//客户端渲染
initialData = props.initialData || {};
}
this.state=initialData;
}
//...
@前端进阶之旅: 代码已经复制到剪贴板
一个正常的项目,都会有多个页面,那么上面的逻辑会出现每一个页面内,而且都是重复的代码。
# 组件componentDidMount存在重复代码
下面代码实现了当没有初始化数据的时候会在客户端进行异步数据获取,然后更新渲染。
另外还会设置当前页面的 title。
逻辑上好像没什么毛病,但是这段代码也会同时出现在h很多页面内。
componentDidMount() {
if (!this.state.fetchData) {
//如果没有数据,则进行数据请求
Index.getInitialProps().then(res => {
this.setState({
fetchData: res.fetchData || [],
page:res.page
});
//设置 title
document.title = res.page.tdk.title;
})
}
if (this.state.page && this.state.page.tdk) {
//设置 title
document.title = this.state.page.tdk.title;
}
}
@前端进阶之旅: 代码已经复制到剪贴板
# 直出的页面无法更新数据
如何理解这个问题?
这个问题隐藏的比较深,如果不仔细观察可能会被忽略。
我就详细的描述的下。
首次进入一个页面/A,/A页面肯定是服务端渲染的,浏览器接管页面后会进行继续渲染,完成页面事件和交互处理。
但是当在浏览器端进行路由切换,再回到这个页面/A时,数据仍然是服务端直出的数据。
无论你切换路由的方式是PUSH还是POP,/A页面的数据永远不会更新。
本骨架现在是通过组件的属性带入直出的数据。
props.initialData
@前端进阶之旅: 代码已经复制到剪贴板
目前我们只实现了通过该属性进行数据的获取,但是缺少路由切换时的更新机制,所以每次切换到/A页面,数据永远都是当初直出的数据。
# 解决问题
# 代码重复问题
前两个代码重复代码的问题应该是比较好解决,可以使用高阶组件来解决,同时还可以统一页面组件内获取数据的属性字段。
比如在服务端或者前端环境都使用 props.initailData 来获取数据,其他逻辑均可以封装在高阶组件内。
高阶组件代码参考
export default (SourceComponent) => {
return class HoComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
initialData: {},
getProps: false//浏览器端是否需要请求数据
}
}
//用于服务端调用
static async getInitialProps(props) {
return SourceComponent.getInitialProps ? await SourceComponent.getInitialProps(props) : {};
}
async com