1

我正在尝试遵循 Ben Awad 的 lireddit 教程。

他展示了如何制作实用程序文件来显示应用程序中的任何身份验证错误。

我认为自从他制作视频以来,下一个/路由器的情况可能已经改变。我正在努力找出一种方法来使用路由器以这种方式在组件内部的钩子内部重定向。

我无法将 useRouter 钩子放在 exchangeError 中 - 我认为原因是当我想在其他组件中使用 exchangeError 时,该钩子不再位于顶层,但是我不知道如何让exchangeError在没有它的情况下工作,或者适应next/router的更新版本。

我最好的尝试(我知道我不能这样使用它)如下:

import { dedupExchange, fetchExchange, createClient, Exchange } from "urql";
import {  pipe, tap } from 'wonka'
import { useRouter } from 'next/router'


const errorExchange: Exchange = ({ forward }) => (ops$) => {
    // where can i put this
    // const Router = useRouter();

    return pipe(
      forward(ops$),
      tap(({ error }) => {
        if (error?.message.includes("not authenticated")) {
        //   Router.replace("/auth/login");
        }
      })
    );
  };

Ben 在 lireddit 上发布的版本是:

const errorExchange: Exchange = ({ forward }) => (ops$) => {
  return pipe(
    forward(ops$),
    tap(({ error }) => {
      if (error?.message.includes("not authenticated")) {
        Router.replace("/login");
      }
    })
  );
};

整个实用程序文件如下:

import { dedupExchange, fetchExchange, createClient, Exchange } from "urql";
import { cacheExchange } from '@urql/exchange-graphcache'
import { MeDocument, LoginMutation, RegisterMutation, MeQuery, LogoutMutation } from "../generated/graphql"
import { betterUpdateQuery } from '../utils/betterUpdateQuery'
import {  pipe, tap } from 'wonka'
import { useRouter } from 'next/router'


const errorExchange: Exchange = ({ forward }) => (ops$) => {
    // where can i put this
    // const Router = useRouter();

    return pipe(
      forward(ops$),
      tap(({ error }) => {
        if (error?.message.includes("not authenticated")) {
        //   Router.replace("/auth/login");
        }
      })
    );
  };


export const createUrqlClient = (ssrExchange: any) => (
    {
        url: 'http://localhost:4000/graphql',
        fetchOptions: {
            credentials: 'include' as const,
        },
        exchanges: [
            dedupExchange,
            cacheExchange({
            updates: {
                Mutation: {
                logout: (_result, args, cache, info) => {
                    betterUpdateQuery<LogoutMutation, MeQuery>(
                    cache,
                    {query: MeDocument},
                    _result,
                    (result, query) => ({me: null})
                    )
                },
                login: (_result, args, cache, info) => {
                    betterUpdateQuery<LoginMutation, MeQuery>(
                    cache,
                    { query: MeDocument },
                    _result,
                    (result, query) => {
                        if (result.login.errors) {
                        return query;
                        } else {
                        return {
                            me: result.login.user,
                        };
                        }
                    }
                    );
                },
                register: (_result, args, cache, info) => {
                    betterUpdateQuery<RegisterMutation, MeQuery>(
                    cache,
                    { query: MeDocument },
                    _result,
                    (result, query) => {
                        if (result.register.errors) {
                        return query;
                        } else {
                        return {
                            me: result.register.user,
                        };
                        }
                    }
                    );
                },
                },
            },
            }),
            errorExchange,
            ssrExchange,
            fetchExchange,
        ],
    } 
)

然后,在创建帖子表单中,此实用程序的使用如下:

import { withUrqlClient } from "next-urql";
import { useRouter } from "next/router";
import React from "react";
import { useCreatePostMutation } from "../generated/graphql";
import { createUrqlClient } from "../utils/createUrqlClient";
import { useIsAuth } from "../utils/useIsAuth";

const CreatePost: React.FC<{}> = ({}) => {
  // const router = useRouter();
  // useIsAuth();
  const [, createPost] = useCreatePostMutation();
  return (
    <Layout variant="small">
      <Formik
        initialValues={{ title: "", text: "" }}
        onSubmit={async (values) => {
          const { error } = await createPost({ input: values });
          if (!error) {
            router.push("/");
          }
        }}
      >

export default withUrqlClient(createUrqlClient)(CreatePost);
4

1 回答 1

0

所以我花了一些时间深入研究源代码。结论:

import { dedupExchange, fetchExchange, createClient, Exchange } from "urql";
import { pipe, tap } from 'wonka'
import Router from 'next/router'

const errorExchange: Exchange = ({ forward }) => (ops$) => {

    return pipe(
      forward(ops$),
      tap(({ error }) => {
        if (error?.message.includes("not authenticated")) {
          Router.router.replace("/auth/login");  // <-- `Router.router` is the way
        }
      })
    );
  };

我不知道他们为什么决定以这种方式公开 API。Router.router对我来说看起来很奇怪,但这就是解决方案。


请注意为什么useRouter钩子不是一个选项。

Hook 必须在 react 组件实例中调用。ButerrorExchange应该被 调用createUrqlClient,而后者又被 调用withUrqlClient(createUrqlClient)(CreatePost)

withUrlClient是一个装饰器,或者反应术语中的 HOC,所以我检查了它调用的时间errorExchange对于一个钩子函数来说是不合适的,因此是一个死胡同。

于 2021-09-21T01:37:45.007 回答