React.JS 一般晚上的教程都是 React + webpack + Router 来搭建的项目. 都是单页项目, 我们将他称为 SPA 项目. 最近有一个项目一开始是使用 React.JS 来的 SPA 项目, 可是后面发现我们这种类型的家居生活馆的项目来说还是要做 SEO, 这操作的.
由于项目是自己可以把控, 了解一下后发现 React.JS 官方是提供了 "同架" 这个概念, 也就是服务端渲染. 可是需要自己搭建和了解它的特性, 还要利用 node 写服务端, 还有客户端. 在时间不允许的情况下, 我最后选了了社区版的 Next.JS. 这可以说是很容易移植的一个框架.
笔者在使用的过程中, 遇到了几处坑, 这里需要提醒一下, 看完后你们不用谷歌, 也不用百度, 看那些人 copy 的 XXX 乐事笔记, 看那些你不如直接看官方文档.
1. 不要使用 NPM run dev 来运行 next.JS
很多文章都是 叫你安装 next.JS 后, 就叫你在 package.JSON 添加
- "scripts": {
- "dev": "next",
- "build": "next build",
- "start": "next start"
- }
然后运行 Next.JS 项目
笔者这里并不推荐这种方法, 由于 Next.JS 访问 static 静态文件必须放到跟目录的 static 夹下面, 你如今做到很多 开发校验 , 服务商都必须你放到跟目录下, 比如 http://www.xxx.com/robots.txt 这样访问路径, 如果在 next.JS
中 是 http://www.xxx.com/static/robots.txt 才能访问到. 这时候服务商就并不能通过你的校验
在项目中任意创建个文件比如 server.JS 内容如下
- const { createServer } = require('http');
- const { parse } = require('url');
- const next = require('next');
- const { join } = require('path');
- const port = parseInt(process.env.PORT, 10) || 3000;
- const App = next({ dev: false }); // 注意这里! 如果你是 false 的时候需要 NPM run build 如果是 true 就是开发模式
- const handle = App.getRequestHandler();
- App.prepare().then(() => {
- createServer((req, res) => {
- const parsedUrl = parse(req.url, true)
- const rootStaticFiles = ['/robots.txt', '/sitemap.xml', '/favicon.ico']
- if (rootStaticFiles.indexOf(parsedUrl.pathname)> -1) {
- const path = join(__dirname, 'static', parsedUrl.pathname)
- App.serveStatic(req, res, path)
- } else {
- handle(req, res, parsedUrl)
- }
- }).listen(port, err => {
- if (err) throw err;
- console.log(`> Ready on http://localhost:${port}`)
- })
- })
rootStaticFiles 定义成文件名称数组, 其实是使用了 next.JS 的中间件处理.
2.Windows location localStorage 对象经常 undefined 导致的 异常错误
由于 Windows location localStorage 这一类都属于客户端 JS, 如果在 node[服务端] 都没有这一类的全局对象.
我发现只要你在 render() , getInitialProps(),componentWillMount() 这三个方法中写客户端全局代码就完全没有问题.
如果非要在 render() 写的话本人推荐是以下写法
- {
- this.state.payTypeValue == 'zhifubao' &&
- <div>
- <form action={`${ApiUri}/v1/alipay/page`} method="post">
- <input type="hidden" value={this.state.order_sn} name="order_sn" />
- <input type="hidden" value={localStorage.getItem('u_token')} name="token" />
- <Button htmlType="submit">
确认支付
- </Button>
- </form>
- </div>
- }
使用 React.Fragment 类的方案让 next.JS 认为你不是在使用服务端渲染.
3.componentWillMount 和 componentDidMount
在 componentWillMount 是不可以添加 jqeruy 第三方插件,
在 componentDidMount 中是可以的
添加 第三方插件库 只要不是 React 组件编写形式 或者 服务端代码都会编译错误 所以不要使用
import xxx from 'xxxx'';
我是建议所有的 客户端代码都要写在 componentDidMount 方法里面, 如果你使用 getInitialProps() 方法渲染的东西在 componentDidMount 并没有任何作用. 必须在 componentWillMount 中赋值才生效.
比如:
- static async getInitialProps({ query }) {
- const result = await http.get('v1/good/search', {
- params: query
- });
- let data = result.data.data;
- let good_list = data.data;
- const res = await http.get('v1/category/tree');
- let menuList = res.data.data;
- return { good_list, menuList, query };
- }
- componentWillMount() {
- const { good_list, menuList } = this.props;
- if (good_list) {
- this.setState({
- good_list
- });
- }
- if (menuList) {
- this.setState({
- menuList
- })
- }
- }
引用第三方插件如下
- componentDidMount() {
- const node = ReactDOM.findDOMNode(this);
- Windows.$ = Windows.jQuery = require('jquery');
- var imagesloaded = require('../../static/vendors/pofo/js/imagesloaded.pkgd.min.js');
- var isotope = require('../../static/vendors/pofo/js/isotope.pkgd.min.js');
- $(node).imagesLoaded(() => {
- $(node).isotope({
- // layoutMode: 'masonry',
- itemSelector: '.grid-item',
- percentPosition: true,
- masonry: {
- columnWidth: '.grid-sizer'
- }
- });
- $(node).isotope('layout');
- })
- Windows.addEventListener('resize', () => {
- setTimeout(() => {
- $(node).isotope('layout');
- }, 500)
- }, false);
- }
4.getInitialProps 产生的 props 只作用 page 的当前操作 JS 文件
如上 提到 如果你使用 getInitialProps() 方法渲染的东西在 componentDidMount 并没有任何作用. 必须在 componentWillMount 中赋值才生效.
如果你 写了一个 React.JS 组件 . 在这个组件里 getInitialProps 你是没有办法 调用到 服务端里面的. 同时你在这个组件里面写任何 http 请求 , 他都只会当作 Ajax (客户端) 操作处理, 解决方法可以在这个组件中使用 React.children, 如果回到父容器中进行渲染, 这样也可以进行服务端渲染.
SPA 我用了一个月多月做的商城应用, 然后移植到 SEO 中也要话个 8 天, 然后解决以上的遇到问题. 感觉成本还是减少了不少, 反正现在百度已经在捉去这个网站了.
如果大家遇到问题可以邮件
来源: https://juejin.im/entry/5c6d649de51d4536ee336078