Есть 2 подхода (которые мне известны) для решения вашей проблемы, и у обоих есть свои плюсы и минусы.
Подход 1 - Использовать маршруты реакции-маршрутизатора для маршрутизации на стороне клиента,и экспресс / koa маршруты для маршрутизации на стороне сервера.
Это в основном то, что вы показали в своем OP - используйте route.get(...)
на стороне сервера и BrowserRouter
на стороне клиента.Этот подход имеет потенциал для создания дубликатов обработки маршрутов (и в отдельных местах), что является самой большой проблемой IMO.Дублирование, однако, не является большой проблемой, поскольку оно может быть сведено к минимуму с помощью обычных модулей.Если вы предпочитаете использовать единственное определение маршрута и более унифицированного решения, читайте дальше, подход № 2.
Подход 2 - Используйте маршруты маршрутизации реакции для маршрутизации на стороне сервера и клиента.
Здесь вы должны использовать StaticRouter
для маршрутизации на стороне сервера и BrowserRouter
для маршрутизации на стороне клиента.Все это очень хорошо изложено в response-router-dom / docs / guides / server-render .Было бы плохо и довольно бессмысленно выполнять копирование и вставку кода из вышеупомянутого документа, но вот некоторые ключевые выводы:
- ваши маршруты теперь находятся в одном общем месте, скажем
./shared/routes.js
ваш js будет выглядеть примерно так:
// app.js
import { routes } from "./shared/routes.js";
const App = () => (
<Switch>
{routes.map(route => (
<Route {...route} />
))}
</Switch>
);
// server.js
import { createServer } from "http";
import React from "react";
import ReactDOMServer from "react-dom/server";
import { StaticRouter } from "react-router";
import App from "./App";
createServer((req, res) => {
const context = {};
const html = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
if (context.url) {
res.writeHead(301, { Location: context.url });
res.end();
} else {
res.write(`
<!doctype html>
<div id="app">${html}</div>
`);
res.end();
}
}).listen(3000);
// or if using express/koa
app.get('/*', (req, res) => {
const context = {};
const app = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
...
})
// client.js
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("app")
);
А если вам нужно получить данные или выполнить какую-либо другую гидратацию на сервере, вы можете использовать методы загрузки данных, описанныездесь: Загрузка данных .
Опять же, этот код не является вашим готовым кодом.Необходимо помнить следующие ключевые моменты:
- создать общее определение маршрута
- на сервере, отобразить маршруты с помощью
StaticRouter
- на клиенте,рендеринг одних и тех же маршрутов с использованием
BrowserRouter
- вы можете использовать обещания или async / await для гидратации приложения на сервере, используя файл определения маршрута, если это необходимо (axios, isomorphic-fetch и т. д. - хорошие библиотеки, которые работают на обоих серверахи клиент одинаково хорошо).
Если я неправильно понял ваш вопрос, и если все, что вы хотите знать, это как создать 2 маршрута, которые могут различать /
и /:id
;тогда, в дополнение к тому, что я упомянул выше, я бы сказал, что теперь нужно просто упорядочить маршруты и сопоставить их с точностью.Таким образом, вы можете сначала определить свой маршрут :/id
, а затем свой маршрут /
, чтобы предотвратить столкновение, или изменить свои маршруты так, чтобы они были семантически правильными, например users/:id
.
реагирующий маршрутизатор (и большинство всех маршрутизаторов) будет соответствовать /
практически для всего.exact
опора делает его консервативным, но это скорее пластырь.Вам было бы лучше, если бы вы оставили /
на своей домашней странице и определили маршруты как entity/:id
в целом.