上下文更新时组件不重新渲染
Component not re-rendering when context is updated
我有一个使用上下文的组件,但在更新上下文时不会重新呈现。
App.tsx
const AppContext = createContext({
isLoggedIn: false,
hasUserLoggedInBefore: false,
});
const useAppContext = () => useContext(AppContext);
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [hasUserLoggedInBefore, setHasUserLoggedInBefore] = useState(
false
);
useEffect(() => {
// to set up initial state
asyncApiCall
.then((result) => {
if (result["user"]) {
setIsLoggedIn(true);
} else {
setIsLoggedIn(false);
}
if (result["hasUserLoggedInBefore"]) {
setHasUserLoggedInBefore(true);
} else {
setHasUserLoggedInBefore(false);
}
});
// to listen for changes
// this does not seem to re-render <UserControl />
listenToOnAuthChangeEvent((user) => {
setIsLoggedIn(true);
setHasUserLoggedInBefore(true);
});
});
return (
<AppContext.Provider
value={{
isLoggedIn,
hasUserLoggedInBefore,
}}
>
<div className="App">
<Routes>
<Route element={<UserControl />}>
<Route path="/" element={<Functionality />} />
</Route>
<Route path="/signup" element={<Signup />} />
<Route path="/login" element={<Login />} />
</Routes>
</div>
</AppContext.Provider>
);
}
以及使用上下文的组件
UserControl.tsx
function UserControl() {
const { isLoggedIn, hasUserLoggedInBefore } = useAppContext();
if (!isLoggedIn) {
return (
<Navigate to={hasUserLoggedInBefore ? "/login" : "/signup"} />
)
}
return (
<Outlet />
)
}
异步 API 调用将获取数据。如果用户未登录,则根据他们过去是否登录过,显示注册页面或登录页面。如果他们已登录,则显示 <Functionality />
.
据我所知,在 API 调用成功并调用 set
方法后,UserControl
组件不会重新渲染以显示 <Functionality />
, <Signup />
组件再次显示。
更新您之前问题的代码框以使用您的 useEffect
和 asyncApiCall
调用 我看到发生的事情是用户从主路径 "/"
开始,因为他们不是通过身份验证,他们将被重定向到 "/signup"
页面。稍后上下文状态会更新,如果您想查看 Functionality
组件,则必须导航回 "/"
。这可能是应用程序在第一次身份验证调用之前做出重定向决定的典型用例,解决方案是使用第三个不确定的“状态”来推迟重定向或呈现插座。
将初始 isLoggedIn
和 hasUserLoggedInBefore
状态更改为未定义。
const [isLoggedIn, setIsLoggedIn] = useState();
const [hasUserLoggedInBefore, setHasUserLoggedInBefore] = useState();
更新 UserControl
身份验证包装器以检查此特定的未定义情况并呈现加载指示器或 null。
function UserControl() {
const { isLoggedIn, hasUserLoggedInBefore } = useAppContext();
// ... snip unrelated code
if (isLoggedIn === undefined) return "... Checking Auth ...";
if (!isLoggedIn) {
return (
<Navigate to={hasUserLoggedInBefore ? "/login" : "/signup"} replace />
);
}
return <Outlet />;
}
这允许应用在将重定向呈现到登录或注册路由或受保护组件的 Outlet
之前等待身份验证状态填充到状态。
我有一个使用上下文的组件,但在更新上下文时不会重新呈现。
App.tsx
const AppContext = createContext({
isLoggedIn: false,
hasUserLoggedInBefore: false,
});
const useAppContext = () => useContext(AppContext);
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [hasUserLoggedInBefore, setHasUserLoggedInBefore] = useState(
false
);
useEffect(() => {
// to set up initial state
asyncApiCall
.then((result) => {
if (result["user"]) {
setIsLoggedIn(true);
} else {
setIsLoggedIn(false);
}
if (result["hasUserLoggedInBefore"]) {
setHasUserLoggedInBefore(true);
} else {
setHasUserLoggedInBefore(false);
}
});
// to listen for changes
// this does not seem to re-render <UserControl />
listenToOnAuthChangeEvent((user) => {
setIsLoggedIn(true);
setHasUserLoggedInBefore(true);
});
});
return (
<AppContext.Provider
value={{
isLoggedIn,
hasUserLoggedInBefore,
}}
>
<div className="App">
<Routes>
<Route element={<UserControl />}>
<Route path="/" element={<Functionality />} />
</Route>
<Route path="/signup" element={<Signup />} />
<Route path="/login" element={<Login />} />
</Routes>
</div>
</AppContext.Provider>
);
}
以及使用上下文的组件
UserControl.tsx
function UserControl() {
const { isLoggedIn, hasUserLoggedInBefore } = useAppContext();
if (!isLoggedIn) {
return (
<Navigate to={hasUserLoggedInBefore ? "/login" : "/signup"} />
)
}
return (
<Outlet />
)
}
异步 API 调用将获取数据。如果用户未登录,则根据他们过去是否登录过,显示注册页面或登录页面。如果他们已登录,则显示 <Functionality />
.
据我所知,在 API 调用成功并调用 set
方法后,UserControl
组件不会重新渲染以显示 <Functionality />
, <Signup />
组件再次显示。
更新您之前问题的代码框以使用您的 useEffect
和 asyncApiCall
调用 我看到发生的事情是用户从主路径 "/"
开始,因为他们不是通过身份验证,他们将被重定向到 "/signup"
页面。稍后上下文状态会更新,如果您想查看 Functionality
组件,则必须导航回 "/"
。这可能是应用程序在第一次身份验证调用之前做出重定向决定的典型用例,解决方案是使用第三个不确定的“状态”来推迟重定向或呈现插座。
将初始 isLoggedIn
和 hasUserLoggedInBefore
状态更改为未定义。
const [isLoggedIn, setIsLoggedIn] = useState();
const [hasUserLoggedInBefore, setHasUserLoggedInBefore] = useState();
更新 UserControl
身份验证包装器以检查此特定的未定义情况并呈现加载指示器或 null。
function UserControl() {
const { isLoggedIn, hasUserLoggedInBefore } = useAppContext();
// ... snip unrelated code
if (isLoggedIn === undefined) return "... Checking Auth ...";
if (!isLoggedIn) {
return (
<Navigate to={hasUserLoggedInBefore ? "/login" : "/signup"} replace />
);
}
return <Outlet />;
}
这允许应用在将重定向呈现到登录或注册路由或受保护组件的 Outlet
之前等待身份验证状态填充到状态。