一边吃零食一边看完了Next.JS的文档,写的不是很复杂,demo尝试起来也很快速:grimacing:

我在看Next.JS文档的时候,是通过yarn init 手动搭建的空项目,然后按照文档一点一点写demo

如果您不喜欢init,可以尝试使用create-next-app,接下来我们也提到一些关于create-next-app的安装和使用

本篇文章主要是对Nextjs文档读后体会,以及发现的新鲜事物,事实上他包含了router等多种服务,后续也会写一下与其他单一组件的区别

NEXT.JS是什么?

粗略看了一下,大概是 就是 一种 reactSSR 同构框架

看一下network,server端渲染还是还是很明显的,个人还是能够接受

等会,插一句,谁还不是个小仙男咋地

创建NEXT.JS 项目

首先安装create-next-app

npm install -g create-next-app

创建Create-next-app项目

create-next-app my-app

这里,官方给出了一些example,你可以直接创建这些Example

create-next-app --example basic-css my-app

create-next-app --example [example-name] [your-app-name]

NextJS总结

SSR 渲染

这是nextjs的关键
nextjs 是在 server render React 的一个框架
那 React 不是前端框架么?所谓三大前端框架之一么 ( Angular,React 和 Vue )

这又在后端渲染 react,到底图个啥呢?后端不是有 express,或者 koakoa2eggjs 等各种框架么?

以前的多页面站点是在服务端渲染的,输出到浏览器时已经有了完整的骨架( html ),这样爬虫抓到时可以分析页面标题,内容等等,做 seo 容易,那时的技术栈是 jsp,php 等等。现在流行的前端框架在这方面是开了倒车,一个空的骨架,一个很大的 js,抓到浏览器以后才开始渲染完整的页面,爬虫就很为难了,因为它没法执行 js 啊,此外,白屏时间也是由于前端渲染带来的问题。于是又有了服务端渲染,让渲染这一步再回到服务端,在服务端模拟浏览器环境,给 react 和 vue 等框架一个可执行的上下文,就是为了提前得到完整的 html。是的,前端就是这么扯蛋。

r u kidding me? 我是混蛋?前端狗?

对样式的支持

  1. 支持style-jsx

当我看到官方给的这个demo的时候,摆弄新耳机的我还以为自己再看vue教程,刷新了一个React小萌新的世界观,原来React也可以这么写

export default () =>
  <div>
    Hello world
    <p>scoped!</p>
    <style jsx>{`
      p {
        color: blue;
      }
      div {
        background: red;
      }
      @media (max-width: 600px) {
        div {
          background: blue;
        }
      }
    `}</style>
    <style global jsx>{`
      body {
        background: black;
      }
    `}</style>
  </div>
  1. 使用 CSS / Sass / Less / Stylus files

支持用.css, .scss, .less or .styl,需要配置默认文件 ,讲道理没有css是世界上最痛苦的事情,不管有没有样式预处理器,css总得支持下吧,何况都支持

静态文件服务

在根目录下新建文件夹叫static。代码可以通过/static/来引入相关的静态资源。

_注意:不要自定义静态文件夹的名字,只能叫static ,因为只有这个名字 Next.js 才会把它当作静态资源。

生成

这里可不是NextJS的提供的组件,而是一种特定的,可以自定义title,meta,这个我从未想过但是细想一下,似乎跟旧项目有些什么相同之处

获取数据以及组件生命周期

相信你注意到,当页面渲染时加载数据,我们使用了一个异步方法getInitialProps。它能异步获取 JS 普通对象,并绑定在props

当服务渲染时,getInitialProps将会把数据序列化,就像JSON.stringify。所以确保getInitialProps返回的是一个普通 JS 对象,而不是Date, Map 或 Set类型。

当页面初始化加载时,getInitialProps只会加载在服务端。只有当路由跳转(Link组件跳转或 API 方法跳转)时,客户端才会执行getInitialProps

注意:getInitialProps将不能使用在子组件中。只能使用在pages页面中。

只有服务端用到的模块放在getInitialProps里,请确保正确的导入了它们,可参考import them properly。 否则会拖慢你的应用速度。

你也可以给无状态组件定义getInitialProps:


const Page = ({ stars }) =>
  <div>
    Next stars: {stars}
  </div>

Page.getInitialProps = async ({ req }) => {
  const res = await fetch('https://api.github.com/repos/zeit/next.js')
  const json = await res.json()
  return { stars: json.stargazers_count }
}

export default Page

getInitialProps入参对象的属性如下:

pathname - URL 的 path 部分
query - URL 的 query 部分,并被解析成对象
asPath - 显示在浏览器中的实际路径(包含查询部分),为String类型
req - HTTP 请求对象 (只有服务器端有)
res - HTTP 返回对象 (只有服务器端有)
jsonPageRes - 获取数据响应对象 (只有客户端有)
err - 渲染过程中的任何错误
可以获取到URL信息,that's great!

nextjs中,生命周期大概是这样的getInitialProps => render =>componentDidMount...

多了一个getInitialProps

Router-Link

值得关注的内容

  1. 拦截器 popstate
import Router from 'next/router'

Router.beforePopState(({ url, as, options }) => {
  // I only want to allow these two routes!
  if (as !== "/" || as !== "/other") {
    // Have SSR render bad routes as a 404.
    window.location.href = as
    return false
  }

  return true
});
  1. URL 对象用法
import Router from 'next/router'

const handler = () =>
  Router.push({
    pathname: '/about',
    query: { name: 'Zeit' }
  })

export default () =>
  <div>
    Click <span onClick={handler}>here</span> to read more
  </div>
http://localhost:3000/about?name='Zeit'
  1. 路由事件

你可以监听路由相关事件。 下面是事件支持列表:

  • routeChangeStart(url) - 路由开始切换时触发
  • routeChangeComplete(url) - 完成路由切换时触发
  • routeChangeError(err, url) - 路由切换报错时触发
  • beforeHistoryChange(url) - 浏览器 history 模式开始切换时触发
  • hashChangeStart(url) - 开始切换 hash 值但是没有切换页面路由时触发
  • hashChangeComplete(url) - 完成切换 hash 值但是没有切换页面路由时触发

4.浅层路由
浅层路由允许你改变 URL 但是不执行getInitialProps生命周期。你可以加载相同页面的 URL,得到更新后的路由属性pathname和query,并不失去 state 状态。

你可以给Router.push 或 Router.replace方法加shallow: true参数。

动态导入

你可以动态导入 JavaScript 模块(如 React 组件)。

动态导入相当于把代码分成各个块管理。Next.js 服务端动态导入功能,你可以做很多炫酷事情。

下面介绍一些动态导入方式:

  1. 基础支持 (同样支持 SSR)
import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(import('../components/hello'))

export default () =>
  <div>
    <Header />
    <DynamicComponent />
    <p>HOME PAGE is here!</p>
  </div>
 
  1. 自定义加载组件
import dynamic from 'next/dynamic'

const DynamicComponentWithCustomLoading = dynamic(
  import('../components/hello2'),
  {
    loading: () => <p>...</p>
  }
)
export default () =>
  <div>
    <Header />
    <DynamicComponentWithCustomLoading />
    <p>HOME PAGE is here!</p>
  </div>
  1. 禁止使用 SSR
import dynamic from 'next/dynamic'

const DynamicComponentWithNoSSR = dynamic(import('../components/hello3'), {
  ssr: false
})

export default () =>
  <div>
    <Header />
    <DynamicComponentWithNoSSR />
    <p>HOME PAGE is here!</p>
  </div>
  1. 同时加载多个模块
import dynamic from 'next/dynamic'

const HelloBundle = dynamic({
  modules: () => {
    const components = {
      Hello1: import('../components/hello1'),
      Hello2: import('../components/hello2')
    }

    return components
  },
  render: (props, { Hello1, Hello2 }) =>
    <div>
      <h1>
        {props.title}
      </h1>
      <Hello1 />
      <Hello2 />
    </div>
})

export default () => <HelloBundle title="Dynamic Bundle" />

这个像 create-react-app?

是或不是.
是,因为它让你的 SSR 开发更简单。
不是,因为它规定了一定的目录结构,使我们能做以下更高级的事:
服务端渲染
自动代码分割
此外,Next.js 还提供两个内置特性:
路由与懒加载组件: (通过引入 next/link)
修改的组件: (通过引入 next/head)
如果你想写共用组件,可以嵌入 Next.js 应用和 React 应用中,推荐使用create-react-app。你可以更改import保持代码清晰。

怎么解决 CSS 嵌入 JS 问题?

Next.js 自带styled-jsx库支持 CSS 嵌入 JS。而且你可以选择其他你喜欢的嵌入方法到你的项目中,可参考文档嵌入样式。

为什么使用新路由?

Next.js 的特别之处如下所示:
路由不需要被提前知道
路由总是被懒加载
顶层组件可以定义生命周期getInitialProps来阻止路由加载(当服务端渲染或路由懒加载时)
因此,它由下面两部分组成:
每个顶层组件都将会收到一个url对象,来检查 url 或修改历史记录
组件用于包装如(<a/>)标签的元素容器,来执行客户端转换。
我们使用了些有趣的场景来测试路由的灵活性,例如,可查看nextgram。

怎么获取数据?

getInitialProps是一个异步函数async(也就是函数将会返回个Promise)。你可以在任意位置获取数据。

就这么简单?这些东西我都用过!

大佬,请留下您的联系方式,我们床上聊

参考:
NextJs官网
create-next-app
create-next-app Example