#node.js #reactjs #react-router #create-react-app #server-side-rendering
#node.js #reactjs #react-маршрутизатор #create-react-app #рендеринг на стороне сервера
Вопрос:
Я просматривал Интернет в течение двух дней, но не могу понять суть реализации SSR с помощью react-routes. Мне потребовалось 5 дней, чтобы как-то разобраться во всем этом без маршрутов. Но теперь я не могу дальше разбираться с использованием react-routes. Вот необходимые детали-
server/server.js
import express from 'express';
import fs from 'fs';
import path from 'path';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import {StaticRouter} from 'react-router-dom';
import App from '../src/App';
const PORT = process.env.PORT || 8080;
const app = express();
app.use(express.static(path.resolve('./build')))
app.get('*', (req, res) => {
fs.readFile(path.resolve('./build/index.html'), 'utf-8', (err, data) => {
if (err) {
console.log(err);
return res.status(500).send('Some error happened');
}
const context = {};
const app = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
)
return res.send(
data.replace(
'<div id="root"></div>',
`<div id="root">${app}</div>`
)
);
});
});
app.listen(PORT, () => {
console.log(`App launched on ${PORT}`);
});
server/index.js
require('ignore-styles')
require('@babel/register')({
ignore: [/(node_module)/],
presets: ['@babel/preset-env', '@babel/preset-react']
})
require('./server')
src/App.js
import React from "react";
import {BrowserRouter, Switch, Route, Link} from 'react-router-dom';
import "./App.css";
function App() {
return (
<BrowserRouter>
<Switch>
<Route path='/' exact component={() => <Link to='/about'>This is Home. Go to About.</Link>} />
<Route path='/about' component={() => <Link to='/'>This is About. Go to Home.</Link>} />
</Switch>
</BrowserRouter>
);
}
export default App;
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.hydrate(<App />, document.getElementById('root'));
serviceWorker.unregister();
Ответ №1:
Удалите BrowserRouter
из приложения и поместите его в свой индексный файл.
index.js
ReactDOM.hydrate(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
App.js
import React from "react";
import { Switch, Route, Link} from 'react-router-dom';
import "./App.css";
function App() {
return (
<Switch>
<Route path='/' exact component={() => <Link to='/about'>This is Home. Go to About.</Link>} />
<Route path='/about' component={() => <Link to='/'>This is About. Go to Home.</Link>} />
</Switch>
);
}
Поскольку <App />
содержит BrowserRouter
, и вы используете его на сервере. BrowserRouter
не может быть обработан на сервере, поскольку для этого требуется DOM.
Кроме того, импортируйте свой StaticRouter
из react-router
not react-router-dom
.
Вы можете проверить документы здесь
import { StaticRouter } from 'react-router';
Комментарии:
1. В чем разница? Он все еще проходит через hydrate.
2.
hydrate
Функция не запускается на сервере. Он выполняется на стороне клиента (в браузере).3. В любом случае он использует dom маршрутизатора react в своем server.js файл, и я думаю, что это проблема.
4. Ооо! Я пропустил это, это тоже одна из проблем.
5. По сути, StaticRouter работает на сервере, а BrowserRouter — на клиенте. Вот и все. Поскольку BrowserRouter неявно получает местоположение из
window.location
клиента, нам нужно явно передать местоположение StaticRouter. После этого все остается по-прежнему.