react,next.js, getInitialProps 自动切换服务端渲染和浏览器
我们已经知道了服务器端渲染的原理,你只需要搭建一个 Express 服务器,在服务器端手工打造『脱水』,在浏览器端做『注水』,完成某个页面的服务器端渲染并不难。 不过,服务器端渲染的问题并不这么简单,一个最直接的问题,就是怎么处理多个页面的『单页应用』(Single-Page-Application)? 所以单页应用,就是虽然用户感觉有多个页面,但是实现上只有一个页面,用户感觉到页面可以来回切换,但其实只是一个页面并没有完全刷新,只是局部界面更新而已。 假设一个单页应用有三个页面 Home、Prodcut 和 About,分别对应的的路径是?/home、/product和?/about,而且三个页面都依赖于 API 调用来获取外部数据。 现在我们要做服务器端渲染,如果只考虑用户直接在地址栏输入?/home、/product?和?/about?的场景,很容易满足,按照上面说的套路做就是了。但是,这是一个单页应用,用户可以在 Home 页面点击链接无缝切换到 Product,这时候 Product 要做完全的浏览器端渲染。换句话说,每个页面都需要既支持服务器端渲染,又支持完全的浏览器端渲染,更重要的是,对于开发者来说,肯定不希望为了这个页面实现两套程序,所以必须有同时满足服务器端渲染和浏览器端渲染的代码表示方式。 读者可以思考一下什么样的代码表示合适,也可以直接往下,看看业界公认最科学的实现方式 Next.js 是如何做的。 快速创建 Next.js 项目 我们也可以手工创建 Next.js 项目,不过更简单的方式是用自动化工具 create-next-app,这个 create-next-app 类似于 create-react-app,一个命令就创建一个可以运行的应用。 首先安装 create-next-app。 npm install -g create-next-app create-next-app next_demo { 讲良心话,Next.js 真的是一个通用性非常高的框架,因为 Next.js 完全遵从了 React 的技术哲学:一切皆为组件。 在 Next.js 中,创造一个页面,其实就是创造一个 React 组件,接下来我们看看如何创建一个页面。 编写页面 npm run dev Next.js 遵从『协定优于配置』(convention over configuration)的设计原则,根据『协定』,在?pages?中每个文件对应一个网页文件,文件名对应的就是网页的路径名,比如?pages/home.js?文件对应的就是?/home?路径的页面,当然?pages/index.js?比较特殊,对应的是默认根路径?/?的页面。 我们修改?pages/index.js,让它更简单一些,如下: import React from ‘react‘ 页面都是 React 组件,这就是 Next.js 的哲学。 getInitialProps 我们用一个函数来实现异步操作,以此模拟调用 API 的延迟效果,如下: const timeout = (ms,result) => { const Home = (props) => ( 注意 getInitialProps 是页面组件的静态成员函数,可以用下面的方法定义: Home.getInitialProps = async () = {...}; class Home extends React.Component { 我们可以这样来看待 getInitialProps,它就是 Next.js 对代表页面的 React 组件生命周期的扩充。React 组件的生命周期函数缺乏对异步操作的支持,所以 Next.js 干脆定义出一个新的生命周期函数 getInitialProps,在调用 React 原生的所有生命周期函数之前,Next.js 会调用 getInitialProps 来获取数据,然后把获得数据作为 props 来启动 React 组件的原生生命周期过程。 这个生命周期函数的扩充十分巧妙,因为: 没有侵入 React 原生生命周期函数,以前的 React 组件该怎么写还是怎么写; 在网页的 HTML 中,可以看到类似下面的内容: <script> 这样一来,如果 getInitialProps 中有调用 API 的异步操作,只在服务器端做一次,浏览器端就不用做了。 那么,getInitialProps 什么时候会在浏览器端调用呢? 当在单页应用中做页面切换的时候,比如从 Home 页切换到 Product 页,这时候完全和服务器端没关系,只能靠浏览器端自己了,Product页面的 getInitialProps 函数就会在浏览器端被调用,得到的数据用来开启页面的 React 原生生命周期过程。 关键点是,浏览器可能会直接访问?/home?或者?/product,也可能通过网页切换访问这两个页面,也就是说 Home 或者 Product 都可能被服务器端渲染,也可能完全只有浏览器端渲染,不过,这对应用开发者来说无所谓,应用开发者只要写好 getInitialProps,至于调用 getInitialProps 的时机,交给 Next.js 处理就好了。 你可以发明自己的服务器端框架,但很可能最后你发现,如果要做得通用性好,最后都会做到和 Next.js 一样的模式上来。 值得一提的是,getInitialProps 返回的应该是“纯数据”,也就是不要返回一个定制类的实例。比如,有一个类 Foo 有一个成员函数 bar,不要在 getInitialProps 返回一个 Foo 实例。不然,经过“脱水”和“注水”过程,网页组件获得的那个“Foo 实例”不再是你想的那个 Foo 实例了,它变成了一个纯粹的数据,不会包含成员函数 bar的。--------------------- 作者:前端工程师来源:CSDN 原文:https://blog.csdn.net/gwdgwd123/article/details/85030708? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |