代码在React 16.8上运行良好,但在> = 16.9时冻结。我查看了16.9的更改,但是当发生无限循环而不是行为的实际更改时,它提到的只是一个额外的警告,所以这不应该发生,而是这样。
将useEffect的依赖项设置为[]确实会破坏循环,但意味着代码需要修改,我不确定如何修改。
以下代码也可以在沙箱here中找到。该版本设置为16.8.4,因此不会冻结。
index.jsx
//...
import { SessionContext, getSessionCookie, setSessionCookie } from "./session";
import "./styles.css";
const history = createBrowserHistory();
const LoginHandler = ({ history }) => {
const [email, setEmail] = useState("");
const [loading, setLoading] = useState(false);
const handleSubmit = async e => {
e.preventDefault();
setLoading(true);
// NOTE request to api login here instead of this fake promise
await new Promise(r => setTimeout(r(), 1000));
setSessionCookie({ email });
history.push("/");
setLoading(false);
};
if (loading) {
return <h4>Logging in...</h4>;
}
return (
//...
);
};
const LogoutHandler = ({ history }: any) => {
//...
};
const ProtectedHandler = ({ history }) => {
//...
};
const Routes = () => {
const [session, setSession] = useState(getSessionCookie());
useEffect(
() => {
setSession(getSessionCookie());
},
[session]
);
return (
<SessionContext.Provider value={session}>
<Router history={history}>
<div className="navbar">
<h6 style={{ display: "inline" }}>Nav Bar</h6>
<h6 style={{ display: "inline", marginLeft: "5rem" }}>
{session.email || "No user is logged in"}
</h6>
</div>
<Switch>
<Route path="/login" component={LoginHandler} />
<Route path="/logout" component={LogoutHandler} />
<Route path="*" component={ProtectedHandler} />
</Switch>
</Router>
</SessionContext.Provider>
);
};
const App = () => (
<div className="App">
<Routes />
</div>
);
const rootElement = document.getElementById("root");
render(<App />, rootElement);
session.ts
import React from "react";
import * as Cookies from "js-cookie";
export const setSessionCookie = (session: any): void => {
Cookies.remove("session");
Cookies.set("session", session, { expires: 14 });
};
export const getSessionCookie: any = () => {
const sessionCookie = Cookies.get("session");
if (sessionCookie === undefined) {
return {};
} else {
return JSON.parse(sessionCookie);
}
};
export const SessionContext = React.createContext(getSessionCookie());
预期结果:应用程序在16.9中起作用,就像在16.8中一样
实际结果:由于在useEffect中存在无限循环,应用程序冻结在16.9中
错误消息:警告:超出最大更新深度。当组件在useEffect中调用setState时会发生这种情况,但useEffect要么没有依赖项数组,要么在每个渲染器上都有一个依赖项更改。
答案 0 :(得分:2)
JSON.parse(sessionCookie)
总是返回一个新对象。
setSession(getSessionCookie())
将会话设置为该新对象
[session]
表示只要在状态中设置了新的会话对象(每次渲染都会发生)就运行。
这就是您所看到的无限循环。要停止它,您可以执行以下操作:
useEffect(
() => {
const newSessionCookie = getSessionCookie()
if(newSessionCookie.uniqueId !== session.uniqueId) {
setSession(getSessionCookie());
}
},
[session]
)
您只需要确保您具有cookie的某些唯一标识符即可。