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
相关产品推荐
相关产品推荐

