简体   繁体   English

反应渲染 JSON 而不是页面重新加载上的组件

[英]React rendering JSON instead of component on page reload

I've deployed my MERN app on Heroku and everything was fine until I realized an issue every time I refresh the page or try to access a route from the address bar.我已经在 Heroku 上部署了我的 MERN 应用程序,一切都很好,直到我每次刷新页面或尝试从地址栏访问路由时都意识到问题。 While navigation through React Router links is fine, trying to go directly to a route from URL address bar or refreshing the page is causing the app to break and sending server responses directly to the browser instead of rendering the component - to clarify: if a given route was supposed to make a GET request and display some data, the actual JSON is displayed on-screen.虽然通过 React Router 链接导航很好,但尝试 go 直接从 URL 地址栏或刷新页面导致应用程序中断并将服务器响应直接发送到浏览器而不是渲染组件 - 澄清:如果给定route 应该发出GET request并显示一些数据,实际的JSON显示在屏幕上。

As far as I've checked, this is happening only on components that make a GET request .据我检查,这仅发生在发出GET request的组件上。

server.js服务器.js

// INITIATE APP
const app = express();

// MIDDLEWARE
app.use(express.json());
app.use(cookieParser());
app.use(cors());
app.use(passport.initialize());

const isProduction = process.env.NODE_ENV === "production";

// Priority serve any static files
isProduction &&
  app.use(express.static(path.resolve(__dirname, "../client/build")));

// CONNECT TO DATABASE
// db config
const dbConnection = isProduction
  ? process.env.MONGO_URI_PROD
  : process.env.MONGO_URI_DEV;

mongoose.connect(dbConnection, () => {
  console.log("Successfully connected to database");
});

// ROUTES
const authRouter = require("./routes/auth");
const detailsRouter = require("./routes/details");
const diaryRouter = require("./routes/diary");
const resultsRouter = require("./routes/results");
const settingsRouter = require("./routes/settings");

app.use("/auth", authRouter);
app.use("/details", detailsRouter);
app.use("/diary", diaryRouter);
app.use("/results", resultsRouter);
app.use("/settings", settingsRouter);

// All remaining requests return the React app, so it can handle routing
isProduction &&
  app.get("*", function (request, response) {
    response.sendFile(path.resolve(__dirname, "../client/build", "index.html"));
  });

// DEFINE PORTS
const port = process.env.PORT || 5000;

// START SERVER
app.listen(port, () => {
  console.log(`Server started on port ${port}`);
});

By the end of the code above, right before Define ports , there is this statement that I included to fix a similar issue happening on other routes too.在上面代码的末尾,就在Define ports之前,我包含了这个语句来解决其他路由上发生的类似问题。 I thought this was going to prevent this error in any situation, but it seems that this isn't the case.我认为这将在任何情况下防止此错误,但似乎情况并非如此。 You can try the app here (you can delete the account on /settings after testing).您可以在这里试用该应用程序(您可以在测试后删除/settings上的帐户)。

I'd like to thank S. Elliott Johnson for the solution I'll post below to anyone running into the same issue in the future:我要感谢S. Elliott Johnson的解决方案,我将在下面发布给将来遇到相同问题的任何人:

This sounds like intended behavior.这听起来像是预期的行为。 Your server routes and your React Router routes SHOULD NOT conflict.你的服务器路由和你的 React Router 路由不应该冲突。

React Router isn't actually "routing" anywhere from a HTTP sense -- it's just rendering different JavaScript/HTML and storing its "location" in the URL. React Router 实际上并没有从 HTTP 意义上“路由”任何地方——它只是渲染不同的 JavaScript/HTML 并将其“位置”存储在 URL 中。

When running a React app, the React app is typically only served from the root of your website (or some other "root", like mydomain.com/app).运行 React 应用程序时,React 应用程序通常仅从您网站的根目录(或其他一些“根目录”,如 mydomain.com/app)提供服务。 When you make a HTTP GET request to that route, the backend server sends all of the JavaScript, HTML, and CSS necessary to bootstrap your React app. When you make a HTTP GET request to that route, the backend server sends all of the JavaScript, HTML, and CSS necessary to bootstrap your React app. Clicking around using React Router simply causes your React code to run on the client.点击使用 React Router 只会让你的 React 代码在客户端上运行。

When you actually reload the page, your browser, as you know, makes a GET request back to the server for that route, so you just get whatever your server sends.如您所知,当您实际重新加载页面时,您的浏览器会针对该路由向服务器发出GET请求,因此您只需获取服务器发送的任何内容。 Let's use a few examples where you have a React app that's served from my domain.com.让我们使用几个示例,其中您有一个从我的域提供的 React 应用程序。com。

Example 1:示例 1:

  • User makes a browser GET request to mydomain.com.用户向 mydomain.com 发出浏览器 GET 请求。 They receive the React app back他们收到了 React 应用程序

  • User navigates to /auth/login - no HTTP requests, React simply running code用户导航到/auth/login - 没有HTTP请求,React 只是运行代码

  • User navigates to /me to view their account -- again, same用户导航到/me以查看他们的帐户 - 再次,相同

  • User reloads the page using the browser - a HTTP GET request is sent to the backend, and they'll receive whatever the backend sends back -- whether that's JSON or something else用户使用浏览器重新加载页面 - HTTP GET请求被发送到后端,他们将收到后端发回的任何内容 - 无论是JSON还是其他

You really have two options here:你真的有两个选择:

  1. Redirect all HTTP requests to root, meaning / , /something and /anything will serve / .将所有HTTP请求重定向到 root,这意味着//something/anything将服务/ Then host your API on another subdomain, like api.mydomain.com然后将您的 API 托管在另一个子域上,例如 api.mydomain.com

  2. Choose a route to serve your API from, like mydomain.com/api .选择一条路线来为您的 API 提供服务,例如mydomain.com/api Forward all requests from any route EXCEPT /api and it's subroutes to the root.转发来自任何路由的所有请求,除了/api和它的子路由到根。

What I ended up doing was option 2:我最终做的是选项2:

Renamed my API routes prepending /api to all of them on server.js .将我的 API 路由重命名为server.js上的所有路由/api Then I renamed all API calls on React accordingly.然后我相应地重命名了所有 API 调用 React。 That code excerpt那段代码摘录

isProduction &&
  app.get("*", function (request, response) {
    response.sendFile(path.resolve(__dirname, "../client/build", "index.html"));
  });

on server.js took care of the GET requests executed on page refresh, making sure that Node always serves index.html to supply those requests. server.js负责处理页面刷新时执行的GET请求,确保 Node 始终为index.html提供这些请求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM