英文:
Inside of useEffect, both condition branches got triggered when refresh page
问题
这是 React 组件中的 useEffect
代码。
import { useSession } from '@supabase/auth-helpers-react'
const session = useSession()
useEffect(() => {
if (session) {
console.debug('保持在页面')
} else {
console.debug('转到登录')
router.push('/login').then(
() => {
console.debug('转到登录完成')
}
)
}
}, [session, router])
它使用 Supabase 管理身份验证(会话)。
在刷新页面时,它存在一个非常奇怪的问题(通过路由进行的登录、登出重定向完全没有问题,只有在刷新页面时才有问题)。两个分支都会被触发,所以在 js 控制台中,我们可以看到两个条件分支的日志。
'保持在页面'
和 '转到登录'
/ '转到登录完成'
。
我假设这是因为刷新后 session
发生了变化。第一次是未定义的,立即触发第二个分支 router.push
,在找到会话时触发第一个分支 保持在页面
。
是否有任何建议可以绕过这个问题?或者有关于在 React/NextJS 中处理页面刷新的良好实践?还有谁之前遇到过类似或相同的问题吗?
英文:
This is the useEffect
code in the React component.
import { useSession } from '@supabase/auth-helpers-react'
const session = useSession()
useEffect(() => {
if (session) {
console.debug('stay in page')
} else {
console.debug('goto login')
router.push('/login').then(
() => {
console.debug('goto login done')
}
)
}
}, [session, router])
It uses a supabase to manage auth (session).
It has a very weid issue when refresh page, (login, logout redirect through router has no issues at all, only when Refresh page.), both branches will be reached, so in js console, we could see logs from both condition branches.
'stay in page'
and goto login
/ goto login done
.
> I assume it is due to session
changed after refresh. 1st time is undefined, to trigger the 2nd brach router.push
, immediately, when session be found, triggers the 1st branch stay in page
.
Is there any suggestion to bypass it? Or any good practice to handle page refresh in React/NextJS? Or anyone has similar or the same issue before?
答案1
得分: 1
在你的代码中,当 session 或 router 的值发生变化时,useEffect
将被执行(useEffect
的第二个参数)。因此,if
和 else
不会在同一次 useEffect
执行中被同时执行,尽管它们可能在快速连续的两次执行中被执行。
以下是实现你想要的方式之一:
- 使用
useState
创建和管理一个变量的状态。 - 在
useEffect
中,通过应用逻辑来设置状态(或不设置状态)以检查 session。 - 在返回语句中,要么渲染当前页面,要么显示登录页面。
一个示例实现:
const App = (props) => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(() => {
// 应用逻辑并设置状态
if (logic) setIsLoggedIn(true);
}, []);
return isLoggedIn ? <ActiveApp /> : <Login />;
}
英文:
In your code, useEffect will be executed whenever value for session or router changes (the 2nd parameter to useEffect). Hence, both if and else are not being executed in the same run of useEffect, albeit, in two different runs that are executed perhaps in quick succession.
Here is one way of achieving what you are after.
- Create and manage the state of a variable using useState
- In the useEffect, set the state (or not) by applying logic to check session
- In the return either render the current page or show the login page.
A sample implementation:
const App = (props) => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(()=>{
//apply the logic and set the state
if(logic) setIsLoggedIn(true);
},[])
return {isLoggedIn ? <ActiveApp /> : <Login />}
}
答案2
得分: 0
终于,我找到了这个问题的根本原因。
这是来自于supabase auth helper的 useSession
钩子,它是一个异步函数,不包括它是否正在加载或出错的状态,这意味着在开始时它将始终为null(这意味着它正在加载)。
解决这个问题的简单方法是,直接使用 useSessionContext
。 session
仍然会以异步方式获取,但 isLoading
和 error
状态可以以同步方式获取,以解决这个问题,并且它们可以用于 useEffect
中的条件分支。
新的代码将如下所示:
import { useSessionContext } from '@supabase/auth-helpers-react'
const {isLoading, session} = useSessionContext()
useEffect(() => {
if (isLoading) {
console.debug('显示加载页面')
}
else if (session) {
console.debug('保持在页面上')
}
else {
console.debug('跳转到登录页')
router.push('/login').then(
() => {
console.debug('跳转到登录完成')
}
)
}
}, [session, isLoading, router])
英文:
Finally, I got the root cause for this.
It is from the useSession
hook from supabase auth helper, it is an async function, and it does not include the state of whether it is loading or error, which it means it will always be null in the beginning (which it means it is in loading).
The simple solution to solve it, is to use useSessionContext
directly instead. session
will still be gotten in an async way, but isLoading
and error
state can be gotten in a sync way to resolve this issue, and they can be used for condition branching inside useEffect
.
New code will be like this:
import { useSessionContext } from '@supabase/auth-helpers-react'
const {isLoading, session} = useSessionContext()
useEffect(() => {
if (isLoading) {
console.debug('show loading page')
}
else if (session) {
console.debug('stay in page')
}
else {
console.debug('goto login')
router.push('/login').then(
() => {
console.debug('goto login done')
}
)
}
}, [session, isLoading, router])
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论