React + Webpack + Router. These are one-page projects, and we call them SPA projects. Recently, there was a SPA project using React. Js at the beginning, but later it was found that SEO was still needed for a project of our type of home and lifestyle museum.

React.js provides the concept of “co-frame”, i.e. server-side rendering. But you need to build and understand its features, but also use Node to write the server, as well as the client. As time didn’t allow, I ended up with the community version of next.js. This is a framework that can be easily ported.

The author in the use of the process, encountered a few pits, here need to remind you, after reading you do not Google, also do not need baidu, look at those people copy XXX Lay notes, look at those you are not as good as directly see the official documents.

1. Do not use NPM run dev to run next.js

Many articles tell you to add it to package.json once you install next

"scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  }
Copy the code

Then run the next.js project

I don’t recommend this method here, because when Next. Js accesses static files, you have to put them in the same directory as static files. You do a lot of development validation these days, and service providers have to put them in the same directory as www.xxx.com/robots.txt. If it is www.xxx.com/static/robo in next.js… In order to access. Then the service provider can’t pass your verification

Create an arbitrary file in your project such as server.js with the following contents

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 }); // Notice here! Const handle = app.getrequesthandler (); NPM run build if you are false 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}`) }) })Copy the code

RootStaticFiles, defined as an array of file names, are actually handled by middleware using next.js.

2. The Windows Location localStorage object is often undefined

Because the Windows Location localStorage class belongs to the client JS, if there is no global object of this class in node [server]. I’ve found that as long as you write client-side global code in render(), getInitialProps(), and componentWillMount(), there’s no problem. If you have to write in render(), I recommend the following

{ 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">Copy the code

Using the React.Fragment class makes next. Js think you’re not using server-side rendering.

3. com ponentWillMount and componentDidMount

Jqeruy third-party plugins cannot be added to componentWillMount. In componentDidMount it’s possible to add a library of third-party plugins to components that aren’t written as React components or server-side code that will compile errors so don’t use import XXX from ‘XXXX ‘;

I’m suggesting that all client code be written inside componentDidMount, if you render something with getInitialProps() it doesn’t have any effect on componentDidMount. Must be assigned to componentWillMount for this to take effect.

Such as:

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
            })
        }
    }
Copy the code
ComponentDidMount () {const node = reactdom.findDomNode (this); window.$ = window.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'); }) window.addEventListener('resize', () => { setTimeout(() => { $(node).isotope('layout'); }, 500) }, false); }Copy the code

4. The props generated by getInitialProps only works on the js file of the current operation of page

As mentioned above if you render something using the getInitialProps() method it doesn’t have any effect on componentDidMount. Must be assigned to componentWillMount for this to take effect.

If you write a react.js component. There is no way to call getInitialProps to the server in this component. Also, any HTTP request you write in this component will only be treated as an Ajax (client-side) operation. The solution is to use the React.children component, which can also be rendered on the server if it is rendered back in the parent container.

SPA I used more than a month to do the mall application, and then transplanted to SEO also want to talk for 8 days, and then solve the above problems. Feeling cost or reduced a lot, anyway now Baidu has caught this website.

If you have any questions you can email [email protected]