英文:
I always get redirected to home page when refresh any page
问题
我在类似情况的主题中进行了探讨,但仍然没有找到解决方案。
当我在 app.js
中实施了检查令牌函数以生成代码,以便未经身份验证的用户重定向到登录页面,而经过身份验证的用户跳转到主页时,我的单页面应用程序开始在刷新/F5时从任何页面重定向到主页。
以下是我的 authContext.js
:
export const AuthContext = createContext({
token: null,
userId: null,
isLoggedIn: false,
login: (userId, token) => {},
logout: () => {},
});
const AuthContextProvider = (props) => {
const [userId, setUserId] = useState();
const [token, setToken] = useState();
const loginUserHandler = useCallback((userId, token) => {
setUserId(userId);
setToken(token);
localStorage.setItem("userData", JSON.stringify({ userId, token }));
}, []);
const logoutUserHandler = useCallback(() => {
setUserId(null);
setToken(null);
localStorage.removeItem("userData");
}, []);
const initialValues = {
userId: userId,
token: token,
isLoggedIn: !!token,
login: loginUserHandler,
logout: logoutUserHandler,
};
return <AuthContext.Provider value={initialValues}>{props.children}</AuthContext.Provider>;
};
export default AuthContextProvider;
和 app.js
代码:
function App() {
const { token, login } = useContext(AuthContext);
let routes;
useEffect(() => {
const storedData = JSON.parse(localStorage.getItem("userData"));
if (storedData && storedData.token) {
login(storedData.userId, storedData.token);
}
}, [login]);
if (token) {
routes = (
<Layout>
<Switch>
<Route path="/home" exact>
<Home />
</Route>
<Route path="/leads-manager" exact>
<Leads />
</Route>
<Route path="/phone-manager" exact>
<Phone />
</Route>
<Route path="/new-notifications" exact>
<Notification />
</Route>
<Redirect to="/home" exact />
</Switch>
</Layout>
);
} else {
routes = (
<Switch>
<Route path="/sign-in" exact>
<Login />
</Route>
<Redirect to="/sign-in" />
</Switch>
);
}
return <BrowserRouter>{routes}</BrowserRouter>;
}
export default App;
希望这能帮助你解决问题。
英文:
I traveled through topics similar situation to mine, but I still not found the solution to my case.
When I implemented checking token function on app.js
to generate code for Unauthenticated User redirect to Signin page and Authenticated User jump to Hompage.
However, after this part my SPA started getting redirect to home page from any page when refreshing/F5.
Below is my authContext.js
:
export const AuthContext = createContext({
token: null,
userId: null,
isLoggedIn: false,
login: (userId, token) => {},
logout: () => {},
});
const AuthContextProvider = (props) => {
const [userId, setUserId] = useState();
const [token, setToken] = useState();
const loginUserHandler = useCallback((userId, token) => {
setUserId(userId);
setToken(token);
localStorage.setItem("userData", JSON.stringify({ userId, token }));
}, []);
const logoutUserHandler = useCallback(() => {
setUserId(null);
setToken(null);
localStorage.removeItem("userData");
}, []);
const initialValues = {
userId: userId,
token: token,
isLoggedIn: !!token,
login: loginUserHandler,
logout: logoutUserHandler,
};
return <AuthContext.Provider value={initialValues}>{props.children}</AuthContext.Provider>;
};
export default AuthContextProvider;
And app.js
code
function App() {
const { token, login } = useContext(AuthContext);
let routes;
useEffect(() => {
const storedData = JSON.parse(localStorage.getItem("userData"));
if (storedData && storedData.token) {
login(storedData.userId, storedData.token);
}
},
此处为隐藏的内容
注册登录后,方可查看
登录
);
if (token) {
routes = (
<Layout>
<Switch>
<Route path="/home" exact>
<Home />
</Route>
<Route path="/leads-manager" exact>
<Leads />
</Route>
<Route path="/phone-manager" exact>
<Phone />
</Route>
<Route path="/new-notifications" exact>
<Notification />
</Route>
<Redirect to="/home" exact />
</Switch>
</Layout>
);
} else {
routes = (
<Switch>
<Route path="/sign-in" exact>
<Login />
</Route>
<Redirect to="/sign-in" />
</Switch>
);
}
return <BrowserRouter>{routes}</BrowserRouter>;
}
export default App;
答案1
得分: 1
问题在于在AuthContextProvider
组件挂载时,您没有从本地存储初始化token
状态。当重新加载页面时,由于React状态仅存在于内存中,所有React状态都将丢失。token
是假值,因此App
组件会呈现“未经身份验证”的路由/重定向。我认为发生的情况是token
是假值,用户被重定向到"/sign-in"
,同时App
中的useEffect
挂钩从本地存储中提取并验证用户,然后更新userId
和token
状态。现在token
被定义,因此会呈现“已验证”的路由,由于URL路径仍然是"/sign-in"
,将呈现Redirect
到"/home"
。
使用useEffect
挂钩来(A)将状态更改持久保存到本地存储,并(B)初始化userId
和token
状态。
const AuthContextProvider = ({ children }) => {
const [userId, setUserId] = useState();
const [token, setToken] = useState();
// 用于初始化本地状态和重新验证的效果
useEffect(() => {
const { userId, token } = JSON.parse(localStorage.getItem("userData")) || {};
if (userId) setUserId(userId);
if (token) setToken(token);
if (userId && token) {
login(userId, token);
}
}, []);
useEffect(() => {
if (token || userId) {
localStorage.setItem("userData", JSON.stringify({ userId, token }));
} else {
localStorage.removeItem("userData");
}
}, [token, userId]);
const loginUserHandler = useCallback((userId, token) => {
setUserId(userId);
setToken(token);
}, []);
const logoutUserHandler = useCallback(() => {
setUserId(null);
setToken(null);
}, []);
const initialValues = {
userId: userId,
token: token,
isLoggedIn: !!token,
login: loginUserHandler,
logout: logoutUserHandler,
};
return (
<AuthContext.Provider value={initialValues}>
{children}
</AuthContext.Provider>
);
};
更新App
组件,以明确检查在组件挂载时token
是否未定义,以便有条件地提前返回,以便不应用“已验证”或“未验证”的路由/重定向逻辑。
function App() {
const { token } = useContext(AuthContext);
if (token === undefined) {
return null; // 或加载指示器/旋转等
}
return (
<BrowserRouter>
{token
? (
<Layout>
<Switch>
<Route path="/home" component={Home} />
<Route path="/leads-manager" component={Leads} />
<Route path="/phone-manager" component={Phone} />
<Route path="/new-notifications" component={Notification} />
<Redirect to="/home" />
</Switch>
</Layout>
)
: (
<Switch>
<Route path="/sign-in" component={Login} />
<Redirect to="/sign-in" />
</Switch>
)
}
</BrowserRouter>
);
}
export default App;
英文:
The issue is that you don't initialize the token
state from localStorage in the AuthContextProvider
component when the component mounts. When you reload the page all React state will be lost since it exists only in memory. token
is falsey and the App
component renders the "unauthenticated" route/redirect. I believe what is happening is the token
is falsey and the user is bounced to "/sign-in"
and at the same time the useEffect
hook in App
pulls from local storage and authenticates the user, which updates the userId
and token
states. token
is defined now and the "authenticated" routes render, and because the URL path is still "/sign-in"
the Redirect
to "/home"
is rendered.
Use useEffect
hooks to (A) persist state changes to localStorage and (B) initialize the userId
and token
states.
const AuthContextProvider = ({ children }) => {
const [userId, setUserId] = useState();
const [token, setToken] = useState();
// Effect to initialize local state and reauthenticate
useEffect(() => {
const { userId, token } = JSON.parse(localStorage.getItem("userData")) || {};
if (userId) setUserId(userId);
if (token) setToken(token);
if (userId && token) {
login(userId, token);
}
}, []);
useEffect(() => {
if (token || userId) {
localStorage.setItem("userData", JSON.stringify({ userId, token }));
} else {
localStorage.removeItem("userData");
}
}, [token, userId]);
const loginUserHandler = useCallback((userId, token) => {
setUserId(userId);
setToken(token);
}, []);
const logoutUserHandler = useCallback(() => {
setUserId(null);
setToken(null);
}, []);
const initialValues = {
userId: userId,
token: token,
isLoggedIn: !!token,
login: loginUserHandler,
logout: logoutUserHandler,
};
return (
<AuthContext.Provider value={initialValues}>
{children}
</AuthContext.Provider>
);
};
Update the App
component to explicitly check if the token
is undefined when the component mounts to conditionally return early so neither the "authenticated" or "unauthenticated" routes/redirect logic are applied.
function App() {
const { token } = useContext(AuthContext);
if (token === undefined) {
return null; // or loading indicator/spinner/etc
}
return (
<BrowserRouter>
{token
? (
<Layout>
<Switch>
<Route path="/home" component={Home} />
<Route path="/leads-manager" component={Leads} />
<Route path="/phone-manager" component={Phone} />
<Route path="/new-notifications" component={Notification} />
<Redirect to="/home" />
</Switch>
</Layout>
)
: (
<Switch>
<Route path="/sign-in" component={Login} />
<Redirect to="/sign-in" />
</Switch>
)
}
</BrowserRouter>
);
}
export default App;
答案2
得分: 0
以下是您提供的代码的翻译:
我稍微修改了代码
我添加了一个额外的状态来检查是否显示`Loader.js`(主要用于防止路由重定向到不需要的路由)
第一次运行项目`hasInitVal = false`会显示`Loader.js`。在`app.js`组件挂载并执行useEffect函数后,`hasInitVal`的值会更改,`app.js`会重新加载,以显示与令牌值相对应的路由。
`autContext.js`文件
```javascript
import { createContext, useCallback, useState } from "react";
export const AuthContext = createContext({
token: null,
userId: null,
isLoggedIn: false,
login: (userId, token) => {},
logout: () => {},
});
const AuthContextProvider = (props) => {
const [userId, setUserId] = useState(null);
const [token, setToken] = useState(null);
const loginUserHandler = useCallback((userId, token) => {
setUserId(userId);
setToken(token);
localStorage.setItem("userData", JSON.stringify({ userId, token }));
}, []);
const logoutUserHandler = useCallback(() => {
setUserId(null);
setToken(null);
localStorage.removeItem("userData");
}, []);
const initialValues = {
userId: userId,
token: token,
isLoggedIn: !!token,
login: loginUserHandler,
logout: logoutUserHandler,
};
return <AuthContext.Provider value={initialValues}>{props.children}</AuthContext.Provider>;
};
export default AuthContextProvider;
app.js
文件
function App() {
const { token, login } = useContext(AuthContext);
const [hasInitVal, setHasInitVal] = useState(false);
useEffect(() => {
const userToken = JSON.parse(localStorage.getItem("userData"));
if (userToken && userToken.userId && userToken.token) {
login(userToken.userId, userToken.token);
}
setHasInitVal(true);
}, [login]);
return (
<Fragment>
{!hasInitVal && <Loader />}
{!token && hasInitVal && (
<Router>
<Routes>
<Route path="/sign-in" element={<Login />} />
<Route path="*" element={<Navigate to="/sign-in" />} />
</Routes>
</Router>
)
{token && hasInitVal && (
<Router>
<Routes>
<Route
path="/home"
element={
<Layout>
<TblContextProvider>
<Home />
</TblContextProvider>
</Layout>
}
/>
<Route
path="/leads-manager"
element={
<Layout>
<TblContextProvider>
<Leads />
</TblContextProvider>
</Layout>
}
/>
<Route
path="/phone-manager"
element={
<Layout>
<TblContextProvider>
<Phone />
</TblContextProvider>
</Layout>
}
/>
<Route path="/new-notifications" element={<Notification />} />
<Route path="*" element={<Navigate to="/home" />} />
</Routes>
</Router>
)}
</Fragment>
);
}
export default App;
希望这些翻译对您有所帮助。如果您有任何其他问题,请随时提出。
英文:
I have changed code a little bit
I added one more state to check display the Loader.js
(mainly for preventing route redirection to hit unwanted routes)
First time runs project hasInitVal = false
will show the Loader.js
. After app.js
component mount and useEffect function get executed, value of hasInitVal
changed and app.js
reload again to display corresponding routes base on the token values.
autContext.js
file
import { createContext, useCallback, useState } from "react";
export const AuthContext = createContext({
token: null,
userId: null,
isLoggedIn: false,
login: (userId, token) => {},
logout: () => {},
});
const AuthContextProvider = (props) => {
const [userId, setUserId] = useState(null);
const [token, setToken] = useState(null);
const loginUserHandler = useCallback((userId, token) => {
setUserId(userId);
setToken(token);
localStorage.setItem("userData", JSON.stringify({ userId, token }));
}, []);
const logoutUserHandler = useCallback(() => {
setUserId(null);
setToken(null);
localStorage.removeItem("userData");
}, []);
const initialValues = {
userId: userId,
token: token,
isLoggedIn: !!token,
login: loginUserHandler,
logout: logoutUserHandler,
};
return <AuthContext.Provider value={initialValues}>{props.children}</AuthContext.Provider>;
};
export default AuthContextProvider;
app.js
file
function App() {
const { token, login } = useContext(AuthContext);
const [hasInitVal, setHasInitVal] = useState(false);
useEffect(() => {
const userToken = JSON.parse(localStorage.getItem("userData"));
if (userToken && userToken.userId && userToken.token) {
login(userToken.userId, userToken.token);
}
setHasInitVal(true);
},
此处为隐藏的内容
注册登录后,方可查看
登录
);
return (
<Fragment>
{!hasInitVal && <Loader />}
{!token && hasInitVal && (
<Router>
<Routes>
<Route path="/sign-in" element={<Login />} />
<Route path="*" element={<Navigate to="/sign-in" />} />
</Routes>
</Router>
)}
{token && hasInitVal && (
<Router>
<Routes>
<Route
path="/home"
element={
<Layout>
<TblContextProvider>
<Home />
</TblContextProvider>
</Layout>
}
/>
<Route
path="/leads-manager"
element={
<Layout>
<TblContextProvider>
<Leads />
</TblContextProvider>
</Layout>
}
/>
<Route
path="/phone-manager"
element={
<Layout>
<TblContextProvider>
<Phone />
</TblContextProvider>
</Layout>
}
/>
<Route path="/new-notifications" element={<Notification />} />
<Route path="*" element={<Navigate to="/home" />} />
</Routes>
</Router>
)}
</Fragment>
);
}
export default App;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论