Reactjs 我如何正确设置它,所以我赢了';是否在未安装的组件上执行状态更新?
我正在用NextJS构建React应用程序Reactjs 我如何正确设置它,所以我赢了';是否在未安装的组件上执行状态更新?,reactjs,typescript,next.js,formik,Reactjs,Typescript,Next.js,Formik,我正在用NextJS构建React应用程序 我构建了一个自定义的LoginGuard组件,如果用户未登录,它将显示登录表单而不是内容 我决定向API发出请求,并使用useSWR保存状态,我使用它构建了一个自定义useUser钩子,它使用/API/user端点来获取用户对象 当我的login函数从API获得响应时,它调用mutate(/API/user) 这会立即重新绘制依赖于useUserhook的所有组件,例如LoginGuard 使用非空的user更新LoginGuard后,它将不再显示我的
LoginGuard
组件,如果用户未登录,它将显示登录表单而不是内容useSWR
保存状态,我使用它构建了一个自定义useUser
钩子,它使用/API/user
端点来获取用户对象login
函数从API获得响应时,它调用mutate(/API/user)
useUser
hook的所有组件,例如LoginGuard
user
更新LoginGuard
后,它将不再显示我的LoginForm
,并将其卸载setSubmitting
回调告诉它何时我已经从服务器获得了更新。但是,因为我在等待login()
承诺后立即调用它,所以在调用它时,组件已经卸载,并且我得到了React错误export-const-LoginGuard:React.FC=({children})=>{
const{user,错误,isValidating}=useUser()
如果(正在验证)返回加载。。。
if(error)return无法加载用户
如果(!用户)
返回(
你应该登录
)
返回(
注销
{儿童}
)
}
导出默认函数LoginForm(){
返回(
{
试一试{
等待登录(输入)
}最后{
设置提交(错误)
}
}}
>
// ...
)
}
导出异步函数登录(请求:LoginRequest){
mutate('/api/user',{user:null},false)
const{data}=wait axios.post('/api/login',request{
validateStatus:(状态)=>[200401]。包括(状态)
})
常量{user}=数据
mutate('/api/user',{user},false)
返回数据
}
导出函数useUser(用户:用户| null=null){
const{data,error,isValidating}=useSWR(
“/api/user”,
{
initialData:{user}
}
)
返回{
用户:数据?用户,
错误,
正在验证
}
}
这就是我得到的错误:
警告:无法对已卸载的组件执行React状态更新
我理解这个错误的含义以及它发生的原因。我也知道一些让它“消失”的方法,但它们看起来像是不雅的黑客
我不明白的是如何构造我的代码,使其不会发生在我身上。我在这里显然犯了一个初学者反应错误,但我不确定确切的位置
另外,使用
useSWR
像用户一样保存全局状态是个好主意吗?结果是,我没有正确理解FormikAPI。我所要做的就是用onSubmit={login}
替换onSubmit
处理程序。它接受承诺,等待承诺,并自行处理提交状态
export const LoginGuard: React.FC = ({ children }) => {
const { user, error, isValidating } = useUser()
if (isValidating) return <div>Loading...</div>
if (error) return <div>Couldn't load user</div>
if (!user)
return (
<div>
You should login
<LoginForm />
</div>
)
return (
<>
<button onClick={logout}>Logout</button>
{children}
</>
)
}
export default function LoginForm() {
return (
<Formik<LoginRequest>
// ...
onSubmit={async (input, { setSubmitting }) => {
try {
await login(input)
} finally {
setSubmitting(false)
}
}}
>
// ...
</Formik>
)
}
export async function login(request: LoginRequest) {
mutate('/api/user', { user: null }, false)
const { data } = await axios.post<LoginResponse>('/api/login', request, {
validateStatus: (status) => [200, 401].includes(status)
})
const { user } = data
mutate('/api/user', { user }, false)
return data
}
export function useUser(user: User | null = null) {
const { data, error, isValidating } = useSWR<{ user: User | null }>(
'/api/user',
{
initialData: { user }
}
)
return {
user: data?.user,
error,
isValidating
}
}