SSR(server-side-render),根据名称咱们都知道叫作服务端渲染,我相信对于工做几年的前端开发者确定很熟悉这个名词,多少也都用过,在这里,我想说的是针对我们刚刚踏入前端圈的朋友们的一点总结和感悟,但愿咱们可以不断的提升对next的认知,相互进步,相互成长!这就是咱们的目标~
其中掘金就使用vue的ssr功能作了全栈服务端渲染,切效果良好。前端
那咱们用next.js的优势是什么呢?
那咱们开始上手吧,hello world!
照作如下步骤吧~复制代码
接着打开package.json添加以下代码,以下:vue
{
"scripts": {
"dev": "next"
}}复制代码
到这里位置项目的准备工做已完成,运行如下命令开启项目服务器node
npm run dev复制代码
那接下来就是建立页面了~~~啦啦啦~~~我学next我开心~~~
next.js是从服务器生成页面,再返回给前端展现。
重点内容开始了哦~~~~复制代码
咱们在pages/index.js中建立一个React函数式组件:react
const Index = () => (
<div>
<p>小英 study next.js</p>
</div>
)
export default Index复制代码
next.js默认使用webpack构建项目,webpack的热部署功能同样能提高开发效率。建立完pages/index.js后,再访问http://localhost:3000便可看到设置好的页面。webpack
很好,不在是咱们不喜欢的404了,看到内容了啊~~ios
再来构建下多页面的吧~
在pages目录下建立文件pages/content.jsweb
export default () => (
<div>
<p>这是content 页面</p>
</div>
)复制代码
打开路由localhost:3000/content,看到咱们新建的第二个页面了。ajax
因此如今咱们明白全部的路由都是经过后端服务器来控制的 ,要想实现客户端路由,须要借助next.js的 Link API,因此接下来咱们看下Link API吧~~
从next/link中能够引用到Link组件。在pages/index.js文件中引用Link,修改以下:express
import Link from "next/link"
const Index = () => (
<div>
<Link href="/content">
<a>去往content页面</a>
</Link>
<p>小英 study next.js</p>
</div>)
export default Index复制代码
咱们使用的Link组件,其实能够当作a标签使用,最终渲染的时候也是a标签,页面渲染以下:npm
点击超连接,便可进入到content页面。下图是实际渲染的结果:
结论:link组件是经过location.history的浏览器API保存历史路由,因此,能够经过浏览器左上角的前进后退按钮来切换历史路由。而在开发过程当中,咱们不须要单独写客户端路由的配置。
next.js是以多页面为中心,只要将页面文件放在pages目录下,就能够经过浏览器上以文件名为路由名来访问到,相反,只要不想让用户经过页面直接访问的组件,都不放在pages目录下,开发者想放在哪一个目录自定义便可。
接下来,咱们建一个components目录,里面建一个公共的Header组件,用于头部导航,经过导航能够再页面间切换。
import Link from 'next/link'
const linkStyle = { marginRight: 15}
const Header = () => (
<div>
<Link href="/">
<a style={linkStyle}>首页</a>
</Link>
<Link href="/content">
<a style={linkStyle}>内容</a>
</Link>
</div>)
export default Header复制代码
好了,定义完组件,咱们在pages/index.js里面引用看一下:
import Header from '../components/Header.js'
const Index = () => (
<div>
<Header />
<p>小英 study next.js</p>
</div>)
export default Index复制代码
在 pages/content.js 中一样引入 Header 组件,在浏览器上经过点击导航切换页面。
import Header from '../components/Header.js'
export default () => (
<div>
<Header/>
<p>这是content 页面</p>
</div>)复制代码
这样就能够再index和content两个页面来回切换了
进一步咱们在封装下Header组件,Layout组件,包含咱们的Header和页面content的组件;
/**Layout**组件/
import Header from './Header'
const layoutStyle = { margin: 0, padding: 0, border: '1px solid #DDD'}
const Layout = (props) => (
<div style={layoutStyle}>
<Header/>
{props.children}
</div>)
export default Layout复制代码
/**在index中使用Layout组件**/
import Layout from '../components/Layout.js'
import Link from 'next/link'
const linkArr = [
'我是连接1',
'我是连接2',
'我是连接3',
'我是连接4',
'我是连接5',
'我是连接6',]
const LinkContent = (props) => (
<li>
<Link href={`tolink?title=${props.title}`}>
<a>{props.title}</a>
</Link>
</li>)
const Index = () => (
<Layout>
<h1>这是个人地盘</h1>
<ul>
{
linkArr.map(item => {
return <LinkContent title={item} />
})
}
</ul>
</Layout>)
export default Index复制代码
页面渲染以下:(如下至关因而列表页,点击列表中的连接至关于到详情页,如下就造成了动态页面之间的跳转)
/**详情页**/
import Layout from '../components/Layout.js'export default (props) => ( <Layout> <h1>{props.url.query.title}</h1> <p>这是不一样title对应的详情页</p> </Layout>)复制代码
总结:使用next.js建立动态页面,与使用React和Vue建立一个spa的页面大致相同, 区别就是页面的渲染主题不一样。
next.js提供一个独特的特性:路由遮盖(Route Masking)。它可使得在浏览器上显示的是路由A,而在app内部实际显示的是路由B。这个特性可使咱们的路由简洁,以上边为例,地址栏显示的是 http://localhost:3000/tolink?title=%E6%88%91%E6%98%AF%E9%93%BE%E6%8E%A56,这个地址含有个title参数,看着很不整洁吗,接下来咱们就要next改造路由,目标是改为 http://localhost:3000/p/0
import Layout from '../components/Layout.js'
import Link from 'next/link'
const linkArr = [ '我是连接1', '我是连接2', '我是连接3', '我是连接4', '我是连接5', '我是连接6',]
const LinkContent = (props) => (
<li>
<Link
as={`p/${props.id}`}
href={`tolink?title=${props.title}`}>
<a>{props.title}</a>
</Link>
</li>)
const Index = () => (
<Layout>
<h1>这是个人地盘</h1>
<ul>
{
linkArr.map((item,index) => {
return <LinkContent id={index} title={item} />
})
}
</ul>
</Layout>)
export default Index复制代码
结论:
- 当在 Link 组件上使用 as 属性时,浏览器上显示的是 as 属性的值,走的是客户端路由,而服务器真正映射的是 href 属性的值,走的是服务端路由。
- 显示 404页面,是由于路由遮盖默认只在客户端路由中有效,要想在服务端也支持路由遮盖,须要在服务端单独设置路由解析的方法。
下面以express为例建立后端服务器讲解如何设置服务器来支持路由遮盖。
先来安装一个express
npm install --save express复制代码
在项目目录下建立server.js文件
const express = require('express')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
server.get('/p/:id', (req, res) => {
const actualPage = '/tolink'
const queryParam = { title: req.param.id }
app.render(req, res, actualPage, queryParam)
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(3000, (err) => {
if(err) throw err
console.log('> ready on http://localhost:3000')
})}).catch(ex => {
console.log(ex.stack)
process.exit(1)
})
复制代码
/**index.js**/
import Layout from '../components/Layout.js'
import { withRouter } from "next/router"
class ToLink extends React.Component {
// 没有该函数是不能实现服务端路由遮盖的
static getInitialProps ({ query: { title } }) {
return { title }
}
render() {
let { title } = this.props
return (
<Layout>
<h1>{title}</h1>
<p>这是不一样title对应的详情页</p>
</Layout>
)
}
}
export default withRouter(ToLink)复制代码
这时在tolink页面刷新的时候就可以正常显示页面了,这里强调一点,我在参考一些文章的时候,没有提到加 getInitialProps这个方法,就说页面刷新就能正常显示是不正确的,本人屡次试验,页面自己的内容是能够正常显示的,可是根据路由获取的title参数是一直拿不到的,加了这个参数就会先去获取参数,这样页面才能完整显示~~~如下提供截图证实:
因此,接下来咱们就说说这个静态的方法。
next.js在react的基础上为组件新增了一个特性:getInitialProps, 同于获取并处理组件的属性,返回组件的默认属性。咱们能够在该方法中请求数据,获取页面须要的数据并渲染返回给前端页面。( 上边的服务端路由遮盖也是用了这个方法,原理就是获取组件的默认属性)
引入一个支持在客户端和服务端发送fetch请求的插件isomorphic-unfrtch, 固然咱们也能够用axios等其余工具。
npm install --save isomorphic-unfetch复制代码
而后修改pages/index.js:
import Layout from '../components/Layout.js'
import { withRouter } from "next/router"
import fetch from 'isomorphic-unfetch'
import Link from 'next/link'
const LinkContent = (props) => {
console.log(props)
return (
<li>
<Link
as={`/p/${props.id}`}
href={{pathname: '/tolink', query: {title: props.title}}}>
<a>{props.title}</a>
</Link>
</li>
)
}
class Index extends React.Component {
static async getInitialProps(){
const res = await fetch('https://api.tvmaze.com/search/shows?q=batman')
const data = await res.json()
console.log(`Show data fetched. Count: ${data.length}`)
return {
shows: data
}
}
render() {
const { shows } = this.props
return(
<Layout>
<h1>这是个人地盘</h1>
<ul>
{
shows.map(( { show } ) => {
return <LinkContent key={show.id} id={show.id} title={show.name} />
})
}
</ul>
</Layout>)
}
}
export default withRouter(Index)复制代码
在getInitialProps中咱们使用async await关键字异步获取咱们须要的参数shows,这样数据就是动态获取的,从而实现动态渲染。注意:getInitialProps不能使用在子组件中。只能使用在pages页面中。
结论以下:
servert.js, 这是我在server.js中添加的一个测试id,只有在服务端渲染的时候,咱们的tolink页面才会获取的这个id
pages/tolink.js,咱们在该页面的 getInitialProps方法中打印一下id
这个结果是我在刷新tolink页面,或者初始化加载的时候,在终端(服务端)打印的结果,有“测试id”这几个字;
继续往下看:
这是我经过首页的列表Link的方式点击进来这个页面,在浏览器控制台打印的结果,很明显这是客户端走的这个方法,是没有”测试id“四个字的,而是undefined,因此这也就验证告终论3的正确性~~~~,(其实我刚开始也是不懂这个意思,如今明白了,但愿正在看的你也能明白哦~~)
Next.js 项目的部署,须要一个 Node.js的服务器,能够选择 Express, Koa 或其余 Nodejs 的Web服务器。本文中以 Express 为例来部署 Next 项目。
为了区分部署环境,咱们须要在 package.json 中修改 script 属性以下:
"scripts": {
"build": "next build",
"start": "NODE_ENV=production node server.js -",
"dev": "NODE_ENV=dev node server.js"
}复制代码
其中,build 命令是用于打包项目,start 命令是用于生产环境部署,dev 命令是用于本地开发。
执行以下命令便可将 Next项目 部署到服务器:
npm run build
npm run start
复制代码
执行完命令后,可在 http://host:3000 访问。其中,host 是指服务器的IP地址。
总结:next.js部署生成环境,必须用build命令打包构建,而后再用start命令部署。
next.js还有不少内容须要咱们不断总结和采坑,未完待续。。。。。。😃😄