typescript Next.js页面冻结选项卡上的Axios请求

nom7f22z  于 2023-01-21  发布在  TypeScript
关注(0)|答案(1)|浏览(144)

想知道如何调试(或从哪里开始)我目前的Axios问题。我有一个Next.js项目(12.3),并有一个Axios拦截器钩子,处理我所有的内部请求。拦截器工作在每个动作/每个页面,但这一特定的页面 */我/设置/密码和安全性/电子邮件/验证 *。
这个特定的操作正在其他几个页面上使用,没有任何问题。即使从工作页面复制整个页面也会冻结选项卡。它在预检中挂起几分钟,然后我得到了[Violation] 'submit' handler took <N>ms的迭代。
下面是我的整个页面:

export default function VerifyEmailForm() {
  const router = useRouter();

  const user: UserState = useSelector((root: RootState) => root.user);
  const [apiError, setApiError] = useState("");
  const [schema, setSchema] = useState<any>();
  const [resubmit, setResubmit] = useState(false);
  const [updateEmail, setUpdateEmail] = useState(false);
  const [submitSuccsess, setSubmitSuccess] = useState(false);

  const [dispatchAxios, { success, loading, error }] = useAxios();

  const initialValues = {
    email: user?.email ? user?.email : "",
  };

  const handleSubmit = async (values: any) => {
    if (!user.email || updateEmail) {
      await dispatchAxios(
        updateUser({
          action: [
            {
              key: "email",
              value: values?.email,
            },
          ],
        })
      );
    }
    await dispatchAxios(requestEmailVerification(values?.email)).then((res) => {
      if (res?.data?.error) {
        setApiError(res?.data?.error);
      } else {
        setResubmit(true);
        setSubmitSuccess(true);
      }
    });
  };

  useEffect(() => {
    const yup = import("yup").then((yup) =>
      setSchema(
        yup.object().shape({
          email: yup
            .string()
            .email("Must be a valid email")
            .required("Email is required"),
        })
      )
    );
  }, []);

  useEffect(() => {
    if (error && !loading) {
      setApiError(error?.message);
    }
  }, [loading, success, error]);

  return (
    <Formik
      validationSchema={schema}
      initialValues={initialValues}
      onSubmit={handleSubmit}
      validateOnBlur={true}
    >
      {({ handleSubmit, setFieldValue, errors, values, touched, isValid }) => {
        return (
          <Form
            onSubmit={handleSubmit}
            onBlur={() =>
              setTimeout(() => {
                setApiError("");
              }, 200)
            }
          >
            <div className="flex flex-wrap gap-9 pb-2.5  ">
              {!user.email || updateEmail ? (
                <div className="w-full relative">
                  <div className="relative w-full">
                    <Field
                      styles="bg-transparent text-center"
                      name="email"
                      type="email"
                      placeholder="Email address"
                      component={InputField}
                      error={errors.email}
                    />
                    {values.email && (
                      <button
                        type="button"
                        onClick={() => setFieldValue("email", "")}
                        className={`flex items-center justify-center bg-background-secondary p-0.5  rounded-full w-4 h-4   absolute bottom-2  ${
                          errors.email ? "right-8 " : "right-2.5 "
                        }`}
                      >
                        <span className="sr-only">Clear Field</span>
                        <XMarkIcon
                          className="text-deactive w-2.5 "
                          aria-hidden="true"
                        />
                      </button>
                    )}
                  </div>
                  <InputError
                    error={errors.email as string}
                    touched={touched?.email as boolean}
                    styles={"flex justify-center"}
                  />
                </div>
              ) : (
                <></>
              )}

              <div className="w-full flex flex-col justify-center items-center">
                <Button
                  type="submit"
                  disabled={!isValid}
                  classes={`w-full text-white p-3  rounded-2xl  mx-8 ${
                    errors.email || !values.email.length
                      ? "border-transparent text-deactive"
                      : "border-2 border-primary"
                  }`}
                  label={resubmit ? "Resend Verification" : "Verify"}
                />
                {user.email && (
                  <Button
                    type="button"
                    classes={`w-full text-white p-3  rounded-2xl mx-8 border-transparent`}
                    label="Update Email"
                    onClick={() => setUpdateEmail(true)}
                  />
                )}
                <Button
                  type="button"
                  classes={`w-full text-white p-3  rounded-2xl mx-8 border-transparent`}
                  label="Cancel"
                  onClick={() => router.back()}
                />
              </div>
            </div>
            <ErrorAlertModal errors={apiError ? [apiError] : undefined} />
            <SuccessAlertModal success={submitSuccsess} />
          </Form>
        );
      }}
    </Formik>
  );
}

下面是我的Axios钩子:

export function useAxios(
  internal: boolean = true
): [DispatchAxios, IAxiosState] {
  const { data: session, status } = useSession();
  const dispatch = useDispatch();
  const isMounted = useRef(true);
  const user: UserState = useSelector((root: RootState) => root.user);
  const env = process.env.NODE_ENV;

  const { logoutUser } = useLogout();

  const client = axios.create({
    //   baseURL: process.env.API_URL,
  });

  client.interceptors.request.use((config: AxiosRequestConfig) => {
    config.headers = config.headers || {};

    if (!config.headers["Content-Type"]) {
      config.headers["Content-Type"] = "application/json";
    }

    if (!config.headers["Ocp-Apim-Subscription-Key"] && env === "production") {
      config.headers[
        "Ocp-Apim-Subscription-Key"
      ] = `${process.env.NEXT_PUBLIC_API_GATEWAY_KEY}`;
    }

    // Internal requests need tokens and other parameters added in.
    if (internal) {
      if (session?.accessToken) {
        config.headers.Authorization = `Bearer ${session.accessToken}`;
      }
    }

    return config;
  });

  const [state, setState] = useState<IAxiosState>({
    loading: false,
    error: null,
    response: null,
    success: false,
  });

  const dispatchAxios: DispatchAxios = useCallback(
    (params: IAxiosAction) => {
      const action: IAxiosAction = {
        type: params.type,
        config: params.config,
        batchOrder: params.batchOrder || [],
      };

      if (params.data) {
        action.data = params.data;
      }

      dispatch({
        ...action,
        loading: true,
      });

      setState({
        ...state,
        error: null,
        response: null,
        loading: true,
        success: false,
      });

      return client(params.config)
        .then((response: AxiosResponse) => {
          // dispatch must come before setState

          if (response.data.err === "INVALID TOKEN") {
            throw action;
          }

          dispatch({
            ...action,
            response,
            loading: false,
          });

          if (isMounted.current) {
            setState({
              ...state,
              loading: false,
              success: true,
              error: null,
              response,
            });
          }
          return {
            success: true,
            error: null,
            response,
          };
        })
        .catch((error: AxiosError) => {
          const originalReq = error.config;

          // Token refresh failed, log user out.
          if (
            originalReq?.url ===
            process.env.NEXT_PUBLIC_AUTH_REFRESH_API_ENDPOINT
          ) {
            // logoutUser();
          }
          // dispatch must come before setState
          dispatch({
            ...action,
            error,
            loading: false,
            success: false,
          });

          if (isMounted.current) {
            setState({
              ...state,
              loading: false,
              success: false,
              response: null,
              error,
            });
          }

          return {
            success: false,
            response: null,
            error,
          };
        });
    },

    [isMounted, dispatch, state, client]
  );

  useEffect(() => {
    isMounted.current = true;
    return () => {
      isMounted.current = false;
    };
  }, [state]);

  return [dispatchAxios, state];
}

updateUser操作正在应用程序的其他几个部分使用,因为用户可以更改和更新他们的配置文件的一部分。正如你所看到的,电子邮件是在这个示例中的目标。我们在另一个页面/me/settings/password&security/email使用这个相同的请求,它解决了刚刚好没有冻结没有挂起。我相信

wgeznvg7

wgeznvg71#

这是我自己导入的moment.js,在 Package 组件中动态导入。
不知何故,它说明了这个问题,不知道为什么

相关问题