想知道如何调试(或从哪里开始)我目前的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
使用这个相同的请求,它解决了刚刚好没有冻结没有挂起。我相信
1条答案
按热度按时间wgeznvg71#
这是我自己导入的moment.js,在 Package 组件中动态导入。
不知何故,它说明了这个问题,不知道为什么