Как настроить вызовы API в приложении MERN Stack (рендеринг на стороне сервера) - PullRequest
2 голосов
/ 05 апреля 2020

Я создал приложение реагирования, отображаемое на стороне сервера, проблема в том, чтобы настроить вызовы API. в основном я хочу получить данные из базы данных, но я не могу понять, как это сделать правильно.

Как вы, возможно, знаете из API-интерфейса stati c MERN App / REST, сервер отправляет данные в соответствии с запрошенные маршруты через свойство data, затем мы получаем его в клиенте с помощью res.data, но в приложении, отображаемом на стороне сервера, я не могу этого сделать, потому что сервер всегда отправляет тег HTML страницы, которую мы запрашиваем клиенту Свойство res.data имеет смысл, но как правильно настроить маршруты таким образом, чтобы мы могли получать и публиковать данные в базу данных в приложении, отображаемом на сервере

Любая помощь будет принята с благодарностью, спасибо за заранее

сервер / сервер. js

import React from "react";
import express from "express";
import compression from "compression";
import { Provider } from "react-redux";
import ReactDOMServer from "react-dom/server";
import { StaticRouter } from "react-router";
import store from "../client/store/store";
import App from "../client/App";
import mongoose from "mongoose";
import path from "path";
import fs from "fs";
import cors from "cors";
import User from "./model/users";

const app = express();
const PORT = process.env.PORT || 3000;

app.use(cors());
app.use(compression());
app.use(express.json());
app.use(express.static("./build/public"));

mongoose
  .connect(
    process.env.MONGODB_URI,
    {
      useNewUrlParser: true,
      useCreateIndex: true,
      useUnifiedTopology: true
    }
  )
  .then(() => {
    console.log("Connected to the Database...");
  })
  .catch(err => console.log("ERROR: " + err));

app.get("*", (req, res) => {
  const content = ReactDOMServer.renderToString(
    <Provider store={store}>
      <StaticRouter location={req.url} context={{}}>
        <App />
      </StaticRouter>
    </Provider>
  );

  const indexFile = path.resolve("./build/public/index.html");
  fs.readFile(indexFile, "utf8", (err, data) => {
    if (err) {
      console.log(err);
      return res.status(500).send("Oops, Something went wrong!");
    }

    return res.send(
      data.replace(
        '<div id="root"></div>',
        `<!DOCTYPE html>
        <html lang="en">
          <head>
            <meta charset="UTF-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0" />
            <meta http-equiv="X-UA-Compatible" content="ie=edge" />
            <title>My App</title>
          </head>
          <body>
            <div id="root">${content}</div>
          </body>
        </html>`
      )
    );
  });
});

// app.get("/api/getData", (req, res) => {
//   User.find({}, (err, users) => {
//     if (err) throw err;
//     res.json({ newUser: users });
//   });
// });

app.listen(PORT, () => {
  console.log("server is listening to port:", PORT);
});

клиент / клиент. js

import "./assets/scss/styles.scss";
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import store from "./store/store";

function importAll(r) {
  let images = {};
  r.keys().map(item => {
    images[item.replace("./", "")] = r(item);
  });
  return images;
}
importAll(require.context("./assets/images", false, /\.(png|jpe?g|svg)$/));

ReactDOM.hydrate(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>,
  document.querySelector("#root")
);

клиент / приложение. js

import React, { Component } from "react";
import { connect } from "react-redux";
import { Route, Switch } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Themes from "./pages/themes";
import Contact from "./pages/Contact";
import ErrorBoundary from "./pages/ErrorBoundary";

class App extends Component {
  render() {
    return (
      <ErrorBoundary>
        <Switch>
          <Route exact path="/" component={Home} />
          <Route exact path="/about" component={About} />
          <Route exact path="/themes" component={Themes} />
          <Route exact path="/contact" component={Contact} />
        </Switch>
      </ErrorBoundary>
    );
  }
}

export default connect()(App);

клиент / страниц / Home. js

import React, { Component } from "react";
import { connect } from "react-redux";
import axios from "axios";

class Home extends Component {
  componentDidMount() {
    axios
      .get("api/getData")
      .then(res => {
        if (res) {
          console.log(res.data);
        }
      })
      .catch(err => console.log(err));
  }

  render() {
    return (
      <div><h1>Welcome Home</h1></div>
    );
  }
}

export default connect()(Home);

1 Ответ

0 голосов
/ 05 апреля 2020

Существует 3 подхода (с подслоями для одного из них):

  1. Имеют разные маршруты для вывода данных HTML (отображаются на сервере) и JSON (оформляется на клиента). Простой и чистый, но многословный.

  2. a. Выведите html как обычно, но проверьте, сделан ли запрос через XmlHttpRequest / XHR, а затем выведите только данные JSON.

  3. b. Выведите html как обычно, но с кодом на стороне клиента добавьте специальный параметр, когда нужно просто вернуть JSON данные. Затем на сервере проверьте, присутствует ли этот параметр. Например, ?output=json.

  4. Отправка JSON данных из базы данных вместе с выводом html. (Это вариант, в котором я не очень уверен, поэтому я оставляю его в качестве идеи)

Вот несколько ресурсов, чтобы дать вам идеи по реакции рендеринга на стороне сервера:

  1. Рендеринг сервера с React и React Router
  2. Рендеринг сервера, обучение React
  3. Использование React Router 4 с сервером -Сайд-рендеринг
  4. act-data-fetching-components, асинхронная загрузка данных для ваших компонентов React с помощью SSR (github)
...