React Context和服务器端渲染:使用React Context进行身份验证的正确方法



我有一个要求,在多个路由中,我需要(重要的是(在服务器上渲染一个静态路由以提高加载速度,这个路由的内容独立于其他路由,现在剩下的路由是互连的,我使用React上下文进行身份验证,我不想在服务器端进行身份验证检查,我只想:

如果->所需路线->显示该页面的服务器呈现内容

否则->继续像以前一样(我不介意这些页面的UI是否也被服务器渲染(

现在我的问题是,在我的案例中,使用上下文的正确方式是什么。这里有一些代码:

/src/index.js(客户端代码(

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import AuthProvider from "./Context/AuthContext";
import ErrorBoundary from "./ErrorBoundary/ErrorBoundary";
import { BrowserRouter } from "react-router-dom";
ReactDOM.hydrate(
<AuthProvider>
<ErrorBoundary>
<BrowserRouter>
<App />
</BrowserRouter>
</ErrorBoundary>
</AuthProvider>,
document.getElementById("root")
);

/src/server/server.js

import path from "path";
import fs from "fs";
import React from "react";
import ReactDOMServer from "react-dom/server";
import express from "express";
import App from "../src/App";
import AuthProvider from "../src/Context/AuthContext";
import ErrorBoundary from "../src/ErrorBoundary/ErrorBoundary";
import { StaticRouter } from "react-router";
const PORT = process.env.PORT || 3006;
const app = express();
app.get("*", (req, res) => {
const markup = ReactDOMServer.renderToString(
<AuthProvider>
<ErrorBoundary>
<StaticRouter location={req.url} context={{}}>
<App />
</StaticRouter>
</ErrorBoundary>
</AuthProvider>
);
const indexFile = path.resolve("./build/index.html");
fs.readFile(indexFile, "utf-8", (err, data) => {
if (err) {
console.error("Something went wrong:", err);
return res.status(500).send("Something went wrong");
}
console.log(req.url)
return res.send(
data.replace('<div id="root"></div>', `<div id="root">${markup}</div>`)
);
});
});
app.use(express.static(path.resolve(__dirname, "..", "build")));
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});

AuthContext.js

import React, { createContext, useState, useEffect } from "react";
import * as AuthService from "../Services/AuthService";
import loadingSvg from "../Assets/loading.gif";
export const AuthContext = createContext();
const Auth = ({ children }) => {
const [user, setUser] = useState(null);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [isLoaded, setIsLoaded] = useState(false);
useEffect(() => {
// Even if refreshed, this is the first api call that is going to happen.
if (localStorage.getItem("user")) {
setUser(JSON.parse(localStorage.getItem("user")));
setIsAuthenticated(true);
setIsLoaded(true);
}
AuthService.isAuthenticated()
.then((data) => {
console.log("isAuth :", data);
if (data.isAuthenticated) {
console.log("Updated Auth Check - ", data);
setUser(data.user);
setIsAuthenticated(data.isAuthenticated);
localStorage.setItem("user", JSON.stringify(data.user));
setIsLoaded(true);
} else {
console.log("There is some error, please login again. ");
setIsLoaded(true);
setIsAuthenticated(false);
localStorage.removeItem("user");
setUser(null);
}
})
.catch((err) => {
console.dir("console err:", err);
console.log("There is some error, please login again. ");
setIsLoaded(true);
setIsAuthenticated(false);
localStorage.removeItem("user");
setUser(null);
});
}, []);
return (
<div>
{!isLoaded ? (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
width: "100vw",
background: "white",
}}
>
</div>
) : (
<AuthContext.Provider
value={{ user, setUser, isAuthenticated, setIsAuthenticated }}
>
{children}
</AuthContext.Provider>
)}
</div>
);
};
export default Auth;

此外,我正在使用cookie进行授权和反应路由器v5。

还有一件事,当我检查页面源时,我得到以下";根";div

<div id="root"><div data-reactroot=""><div style="display:flex;justify-content:center;align-items:center;height:100vh;width:100vw;background:white"></div></div></div>

因此服务器端渲染失败(?(

我认为只要身份验证代码在useEffect中,它就会只运行客户端。因此,您不应该更改任何内容,您的代码应该按原样工作。

服务器渲染将使用传递给提供的上下文的初始值来完成。然后,当组件在客户端水合时,将运行useEffect回调,并更新值。

useEffect、componentDidMount和其他生命周期方法不在服务器端运行。因此,这是推迟服务器执行某些逻辑的好方法。

最新更新