Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 我如何正确设置它,所以我赢了';是否在未安装的组件上执行状态更新?_Reactjs_Typescript_Next.js_Formik - Fatal编程技术网

Reactjs 我如何正确设置它,所以我赢了';是否在未安装的组件上执行状态更新?

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后,它将不再显示我的

我正在用NextJS构建React应用程序

  • 我构建了一个自定义的
    LoginGuard
    组件,如果用户未登录,它将显示登录表单而不是内容
  • 我决定向API发出请求,并使用
    useSWR
    保存状态,我使用它构建了一个自定义
    useUser
    钩子,它使用
    /API/user
    端点来获取用户对象
  • 当我的
    login
    函数从API获得响应时,它调用
    mutate(/API/user)
  • 这会立即重新绘制依赖于
    useUser
    hook的所有组件,例如
    LoginGuard
  • 使用非空的
    user
    更新
    LoginGuard
    后,它将不再显示我的
    LoginForm
    ,并将其卸载
  • 我用Formik构建了这个登录表单。在其中,我使用
    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
        }
    }