Server rendering introduction:

Advantages:

1. Better SEO, conducive to search engines to capture page information.

2. Speed up the first screen rendering.

There are two cases of general use:

1. Request the interface to return HTML, and the server will render a single page and return it to the front end.

2. Front-end projects are placed in the Node environment to render and run, which is equivalent to developing projects in Node.

The preparatory work

Create a project:

Don’t use TS to get rid of –typescript

npx create-react-app ssr-demo --typescript
Copy the code

Create node code backbone:

Create two JS files

App.js is used to store the main Node code, and new start.js and. Babelrc are used to configure Babel.

Since Node does not support ES6, React, etc., we need to introduce Babel:

npm i babel-cli babel-preset-env babel-preset-react babel-preset-stage-0
Copy the code

start.js

require('babel-polyfill');
require('babel-register');
require('./server/app.js');
Copy the code

.babelrc

{
  "presets": [
    "env"."stage-0"."react",]}Copy the code

app.js

// import express from 'express'; 
const express = require('express');
const app = express();

const config = {
  port: 8000,
}

app.get('/', (req, res) => {
  res.send('hello~! ');
})

app.listen(config.port, () => {
  console.log('Boot: 127.0.0.1:${config.port}`);
})
Copy the code

Configure node hot update:

Hot updates to Node require the installation of two plug-ins:

Cross-env: configures environment variables across platforms

Nodemon: Hot update of a node

npm i cross-env nodemon
Copy the code

Add the following statement to the package.json file.

The entire development environment is now configured.

Interface returns HTML

Try to return the full HTML to the front end and change the code in app.js to:

const express = require('express');
const fs = require('fs');
const app = express();
const config = {
  port: 8000,
}

app.get('/', (req, res) => {
  // res.send('hello~!! ');
  var index = fs.readFileSync('./public/index.html');
  var html = index.toString();
  res.send(html);
})

app.listen(config.port, () => {
  console.log('Boot: 127.0.0.1:${config.port}`);
})
Copy the code

Public index. HTML

Run NPM run hot to see the result:

React component rendering

Here comes the most important part! Create a folder compontents in the server directory and create the demo.js file inside:

Create component demo in demo.js:

import React from 'react';

class Demo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      mytext: 'the default 1'
    }
    this.change = this.change.bind(this);
  }

  change(e) {
    this.setState({
      mytext: e.target.value
    })
  }

  render() {
    return (
      <div className="App">
        <h2>{this.state.mytext}</h2>
        <input value={this.state.mytext} onChange={this.change}></input>
      </div>)}}export default Demo;
Copy the code

Introduce use in app.js

React and react-dom/server

const express = require('express');
const fs = require('fs');
const app = express();
const config = {
  port: 8000,}import React from 'react';
import ReactDOMServer from 'react-dom/server';

import Demo from './compontents/demo';

app.get('/', (req, res) => {
  var index = fs.readFileSync('./public/index.html');
  // renderToString, renderToStaticMarkup
  var demo = ReactDOMServer.renderToString(<Demo />); var html = index.toString().replace('hello~! ', demo); res.send(html); }) app. Listen (config. The port () = > {the console. The log (` start: 127.0.0.1: ${config. The port} `); })Copy the code

The results:

The component has been rendered.

Focus on renderToString and renderToStaticMarkup

RenderToString: Render with either data-reactid or data-reactroot properties. (Data-reactid is displayed when parameters are passed between components, data-reactroot is displayed when no parameters are passed)

RenderToStaticMarkup: There is no data-reactid/data-reactroot attribute, pure HTML, can save a little traffic.

What does data-reactid/data-reactroot do?

React recognizes data-reactid in the client and does not render front-end code overwrites. If there is no data-reactid front-end, it ignores server elements and overwrites them.

Binding approach

It is clear that the Demo component has a binding change event to change the mytext parameter, but how to input no effect, because the server rendered just pure HTML, just for display.

How to bind methods, events, and styles?

This is why you put the Node code in create-react-app.

Copy the component of the server to the SRC directory.

There is the isomorphism principle, so the development must ensure that the server components and front-end components are consistent (server component === SRC component).

Modify the App. The TSX

import React from '.. /node_modules/@types/react';
import './App.css';
import Demo from './compontents/demo';

const App: React.FC = (a)= > {
  return (
    <div>
      <Demo/>
    </div>
  );
}

export default App;
Copy the code

NPM start

Running React on the client side has styles and events, but the HTML available to the client is first loaded without rendering the component content.

The first load renders the component, and the code above has been implemented, now it is time to introduce the style and associated JS:

npm run build
Copy the code

Modify app.js in the server

const express = require('express');
const fs = require('fs');
const app = express();
const config = {
  port: 8000,
}

import React from 'react';
import ReactDOMServer from 'react-dom/server';

import Demo from './compontents/demo';

app.get('/', (req, res) => {var index = fs.readfilesync ('./build/index.html');
  var demo = ReactDOMServer.renderToString(<Demo />);
  var html = index.toString().replace('hello~! ', demo); res.send(html); }) app. Listen (config. The port () = > {the console. The log (` start: 127.0.0.1:${config.port}`);
})

Copy the code

App.use (‘/’, express.static(‘./build’))

app.js

const express = require('express');
const fs = require('fs');
const app = express();
const config = {
  port: 8000,
}

import React from 'react';
import ReactDOMServer from 'react-dom/server';

import Demo from './compontents/demo';

app.get('/', (req, res) => {
  var index = fs.readFileSync('./build/index.html');
  var demo = ReactDOMServer.renderToString(<Demo />);
  var html = index.toString().replace('hello~! ', demo);
  res.send(html);
})

app.use('/', express.static('./build')); App.listen (config.port, () => {console.log(' boot: 127.0.0.1:${config.port}`);
})
Copy the code

You can see that the Demo component already exists in HTML when first rendered, and that the styles and events are normal:

At this point, the entire server rendering is complete