You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Router中Link组件点击不等待async/await代码块执行问题求解

问题根源
  • <Link> 组件自带点击后立即跳转的默认行为,你的代码仅在校验失败时调用了 event.preventDefault() 阻止跳转,校验通过时没有阻止默认行为,所以不等异步代码执行完成就会触发路由跳转。
  • <Link> 没有提供手动触发跳转的公开API,即便你全局阻止默认行为,也无法在异步结束后主动触发<Link>的跳转逻辑,因此该场景不适合直接用<Link>包裹按钮实现需求。
符合要求的解决方案

你不需要通过props传递history/navigate实例,直接使用React Router提供的内置Hook即可在组件内部获取导航能力,无需父组件传参,实现逻辑比硬改造<Link>更简洁。

React Router v6 实现代码

import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
// 引入useNavigate Hook
import { useNavigate } from 'react-router-dom';
import { toast } from 'react-toastify';

const StyledButton = styled.button`
  width: 100%;
  border-radius: 10px;
  background-color: #24b571;
  color: #ffffff;
  font-weight: bold;
  margin-bottom: 5px;
  // 加载状态下禁用按钮,避免重复点击
  &:disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }
`;

const SaveButton = ({
  children,
  saveValidation,
  message,
  to,
  setIsLoading,
  isLoading, // 补充loading状态参数,用于禁用按钮
}) => {
  // 组件内部获取导航实例,无需父组件传递
  const navigate = useNavigate();

  const promiseFunc = () =>
    new Promise((resolve) => {
      setTimeout(() => {
        resolve(5);
      }, 5000);
    });

  const onClickHandler = async () => {
    setIsLoading(true);
    const control = saveValidation();
    if (!control) {
      toast.error(message);
      setIsLoading(false);
      return;
    }
    try {
      const a = await promiseFunc();
      alert(a);
      // 异步逻辑执行成功后再跳转
      navigate(to);
    } catch {
      alert('error');
    } finally {
      setIsLoading(false);
    }
  };

  // 去掉外层Link,直接用按钮绑定点击事件
  return (
    <StyledButton onClick={onClickHandler} disabled={isLoading}>
      {children}
    </StyledButton>
  );
};

export default SaveButton;

SaveButton.propTypes = {
  children: PropTypes.node.isRequired,
  saveValidation: PropTypes.func.isRequired,
  to: PropTypes.string.isRequired,
  message: PropTypes.string,
  setIsLoading: PropTypes.func,
  isLoading: PropTypes.bool,
};
SaveButton.defaultProps = {
  message: 'Fill all values',
  setIsLoading: () => {},
  isLoading: false,
};

React Router v5 适配方案

仅需要把导航相关的代码替换为useHistory即可:

// 引入useHistory
import { useHistory } from 'react-router-dom';

// 组件内部获取实例
const history = useHistory();

// 跳转逻辑替换为
history.push(to);

内容的提问来源于stack exchange,提问作者Neo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 15:36:04