在重定向之前需要反应上下文来更新
Posted
技术标签:
【中文标题】在重定向之前需要反应上下文来更新【英文标题】:Need react context to update before redirect 【发布时间】:2021-05-29 03:47:13 【问题描述】:我有一个UserContext
,它在App
呈现时设置。 App
从服务器检索当前用户,然后在提供程序中设置用户上下文。
所以每当我导航到一个链接时,App
会呈现,从服务器获取当前用户并设置它。这允许所有孩子都可以访问该用户。
<Redirect>
的问题
但是我在使用<Redirect>
时遇到了问题。
如果用户在服务器上更新,那么App
需要重新渲染才能获得更新的用户对象。
但是在重定向时 App
不会重新渲染,这会导致用户上下文过时,直到用户刷新页面以重新渲染 App
。
示例:登录查看您的个人资料
在下面的代码中,我有一个登录按钮。当用户登录时,页面会重定向到他们的个人资料。
但是即使用户在服务器上成功登录,用户上下文也没有更新。这是因为重定向不会重新渲染App
。
有没有办法重定向到重新渲染应用程序或其他解决方案?
代码
相关代码如下。
完整代码可在repo here 上找到。下载并运行npm i
、npm start
,然后在调试器中选择并播放Compounded Server/React
或运行node currentUserServer/server.js
以在不使用调试器工具的情况下启动服务器。
前端
App.js
import React, useEffect, useContext, useState from "react";
import UserContext from "./contexts/UserContext";
import BrowserRouter as Router, Switch, Route from "react-router-dom";
import Login from "./Login";
import Profile from "./Profile";
const currentUser = async () =>
const user = await fetch("/users/current", ).then(async (res) =>
const userJson = await res.json();
return userJson;
);
return user;
;
export default function App()
const [user, setUser] = useState(null);
useEffect(() =>
currentUser().then((user) =>
setUser(user);
);
, []);
return (
<Router>
<div className="App">
<UserContext.Provider value=user>
<Switch>
<Route path="/profile">
<Profile />
</Route>
<Route path="/">
<Login />
</Route>
</Switch>
</UserContext.Provider>
</div>
</Router>
);
登录.js
import React, useContext, useState from "react";
import Redirect from "react-router-dom";
import UserContext from "./contexts/UserContext";
export default function Login()
const [next, setNext] = useState(false);
const currentUser = useContext(UserContext);
return (
<div>
Logged In:" "
!currentUser || currentUser.message === "not logged in"
? "No One"
: currentUser.username" "
<br></br>
<button
onClick=() =>
fetch("/login", method: "POST" ).then((res) =>
if (res.status === 201) setNext(true);
);
>
Login
</button>
<button
onClick=() =>
fetch("/logout", method: "DELETE" );
>
Logout
</button>
next && <Redirect to="/profile" />
</div>
);
Profile.js
import React, useContext from "react";
import UserContext from "./contexts/UserContext";
export default function Profile()
const currentUser = useContext(UserContext);
return (
<div>
currentUser && !currentUser.message
? "You're logged in and can edit your profile."
: "You're not logged in."
</div>
);
【问题讨论】:
仅供参考: 使用async
/await
,您可以获取just three lines 中的用户。
【参考方案1】:
我找到了两种解决方案。
#1 快速修复但效果不佳:setRefresh
这可行,但似乎取消了使用上下文的全部意义,因为我们必须向下传递状态。
我在App.js
上创建了一个refresh
状态,触发useEffect
。
useEffect(() =>
if (refresh)
currentUser().then((user) =>
setUser(user);
setRefresh(false);
);
, [refresh]);
现在我可以将setRefresh
作为道具传递给Login
以触发useEffect
再次运行。
Full code here
#2 更好! setUser
和 getUser
在上下文中
这有点像上面的解决方案,但它使您仍然可以利用上下文。您将 setUser
和 getUser
方法放在上下文中 - 受此 answer 启发。
在app.js
中,我们创建了一个user
状态。我们将UserContext
的值设置为一个对象。该对象包含user
和setUser
。我们还传入了getUser
,这是一个从服务器请求当前用户的函数。
export default function App()
const [user, setUser] = useState(null);
const getUser = async () =>
const user = await fetch("/users/current", ).then(async (res) =>
const userJson = await res.json();
return userJson;
);
return user;
;
const value = user, setUser, getUser ;
这里将对象传递给提供者。
<UserContext.Provider value=value>
现在,只要有UserContext
消费者,我们就可以访问user
、setUser
、getUser
。
const user, setUser, getUser = useContext(UserContext);
我们可以使用getUser
ping 当前用户的服务器。然后将该结果设置为user
。
setUser(await getUser());
export default function Login(props)
const [next, setNext] = useState(false);
const user, setUser, getUser = useContext(UserContext);
return (
<div>
Logged In:" "
!user || user.message === "not logged in" ? "No One" : user.username" "
<br></br>
<button
onClick=() =>
fetch("/login", method: "POST" ).then(async (res) =>
if (res.status === 201)
setUser(await getUser());
setNext(true);
);
>
Login
</button>
Full Code here
【讨论】:
以上是关于在重定向之前需要反应上下文来更新的主要内容,如果未能解决你的问题,请参考以下文章