Formik结合React Router使用时如何实现仅表单验证通过才跳转路由
解决方案
核心问题原因
你当前的写法存在两个核心问题:
- 按钮被嵌套在
<Link>组件内部,<Link>的默认跳转行为会在点击时直接触发,不会等待按钮onClick事件内的校验、提交逻辑执行完成,和你预期的「先校验再跳转」逻辑冲突。 Formik的handleSubmit、校验逻辑都是异步执行的,你在调用handleSubmit后立刻读取isValid属性,拿到的还是校验执行前的旧状态,判断结果自然不准确。同时表单未被触碰时,Formik默认不会将未操作字段的错误展示出来,也会导致你说的空白表单场景不符合预期。
修复方案
不要用<Link>包裹按钮,改为使用React Router的编程式导航,等表单校验确认通过后再手动触发路由跳转,具体实现如下:
第一步:注入路由能力
如果是类组件,使用withRouter高阶组件注入路由操作对象:
import { withRouter } from 'react-router-dom'; // 你的原有组件 class YourFormComponent extends React.Component { // 原有逻辑 } // 导出时用withRouter包裹,组件props就可以拿到history对象 export default withRouter(YourFormComponent);
如果是函数组件,可以直接用useNavigate钩子实现导航。
第二步:修改按钮结构
移除外层的<Link>包裹,直接保留按钮:
{!this.props.disabled && ( <button className="buttons-panel__button" type="button" onClick={this.handleSave} > Save </button> )}
第三步:实现校验+跳转逻辑
新增handleSave方法,先手动触发表单全量校验,确认无错误后再执行提交和跳转,同时标记错误字段为已触碰,保证错误提示正常展示:
handleSave = async () => { // 手动触发表单全量校验,拿到所有错误 const errors = await this.props.formikProps.validateForm(); const hasError = Object.keys(errors).length > 0; if (hasError) { // 把所有存在错误的字段标记为已触碰,强制展示错误提示 const touchedFields = Object.keys(errors).reduce((res, field) => { res[field] = true; return res; }, {}); this.props.formikProps.setTouched(touchedFields); this.onValidationFail(); return; } // 校验通过,执行提交逻辑后跳转 this.props.handleSubmit(false); this.props.history.push('mainMenu'); }
这个方案可以覆盖所有场景,包括表单完全未触碰的情况,校验不通过时不会触发路由跳转,同时所有错误字段都会正常展示提示。
内容的提问来源于stack exchange,提问作者mgzparanoid
相关产品推荐
相关产品推荐

