网络数据的请求,是现代网页的最基本组成部分。一起看一下 nextjs 怎么实现的。

nextjsReact.Component 组件提供了 getInitialProps 钩子函数。这里我们新建一个文件 req.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// req.js
import React, { Component } from 'react';

export default class extends Component {
static async getInitialProps({ req }) {
const userAgent = req ? req.headers['Accept'] : navigator.Accept;
return { userAgent };
}

render() {
return (
<div>
Hello World {this.props.userAgent}
</div>
);
}
}

启动项目,访问 localhost:3000/req,页面上会输出我们本次请求的 user-agent(用户代理) 信息。

回过头来看一下代码,使用了 async ES7 关键字,表示 getInitialProps 异步执行,这样可以加快服务端的渲染速度。

我们可以修改 req.js 代码如下,看一下组件的挂载周期。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// req.js
import React, { Component } from 'react';

export default class extends Component {
static async getInitialProps({ req }) {
console.log('getInitialProps');
const userAgent = req ? req.headers['user-agent'] : navigator.userAgent;
return { userAgent };
}

constructor(props) {
super(props);
console.log('constructor');
}

componentWillMount() {
console.log('componentWillMount');
}

componentDidMount() {
console.log('componentDidMount');
}

render() {
console.log('render');
return (
<div>
Hello World {this.props.userAgent}
</div>
);
}
}

查看浏览器控制台:

1
2
3
4
constructor
componentWillMount
render
componentDidMount

查看服务器控制台:

1
2
3
4
getInitialProps
constructor
componentWillMount
render

浏览器控制台并没有打印出 getInitialProps 钩子方法中的输出内容。

事实上,对于初始页面加载,getInitialProps 将仅在服务器上执行。getInitialProps 只有在通过Link组件导航到不同的路由或使用路由API 时,才能在客户端上执行。

getInitialProps 只能在 pages/ 下的组件中使用,不能再子组件中使用。

可见,如果我们要进行接口数据的请求,可以放在 getInitialProps 服务器端执行。

下面是一个使用无状态方法实现 React 组件的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// req.js
import React from 'react';
// npm install isomorphic-fetch -S 安装 fetch 依赖
import fetch from 'isomorphic-fetch';

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 方法中可利用的属性:
/req?a=aa&b=bb 请求地址:

  • pathname - URL 中的路径部分 /req
  • query - URL 参数部分解析为对象 /req?a=aa&b=bb => { a: 'aa', b: 'bb' }
  • asPath - 浏览器中显示的实际路径 /req?a=aa&b=bb
  • req - HTTP request object (仅服务器)
  • res - HTTP response object (仅服务器)
  • jsonPageRes - 服务器返回对象 (仅浏览器)
  • err - 渲染过程中遇到的任何错误