React中Yup本地化初始化晚于校验Schema的执行顺序问题
问题根因
ES模块的静态导入机制会在代码执行前,优先解析并运行所有被导入模块的顶层代码。哪怕你在index.tsx里把initLocale()写在了ReactDOM.render前面,只要siteFormValidationSchema所在的模块被同步导入(比如路由里直接引入Settings组件,组件又同步import了schema),那schema模块里的顶层代码(包括console.log和Schema创建)会先于index.tsx里的initLocale()执行——因为import的解析是在所有代码执行阶段之前完成的,和组件是否被渲染无关。
解决办法
1. 把Schema改成延迟创建的函数
把Schema的定义逻辑封装成函数,只在实际需要校验的时候调用,确保此时initLocale()已经执行完毕:
// /src/components/settings/siteForm/schema.ts import { string, number, object } from 'yup'; // 用函数包裹,延迟创建Schema export const getSiteFormValidationSchema = () => { return object().shape({ name: string().required().max(20), }); };
在表单组件里使用时再调用函数:
// Settings表单组件内 import { getSiteFormValidationSchema } from './schema'; // 组件初始化或校验前调用 const validationSchema = getSiteFormValidationSchema();
2. 用动态导入延迟加载Schema所在模块
如果用React Router,可以在路由层面动态导入Settings组件,这样只有用户访问/settings时才会加载对应的Schema模块,此时initLocale()早已执行完成:
// 路由配置文件 import { lazy, Suspense } from 'react'; import { Routes, Route } from 'react-router-dom'; // 动态导入Settings组件 const Settings = lazy(() => import('./components/settings/Settings')); function App() { return ( <Suspense fallback={<div>加载中...</div>}> <Routes> <Route path="/settings" element={<Settings />} /> {/* 其他路由 */} </Routes> </Suspense> ); }
3. 在Yup工具模块提前初始化本地化
修改你的/libs/yup模块,在导出Yup方法前直接完成本地化配置,这样所有导入该模块的地方都会用已经本地化的Yup:
// /libs/yup.ts import * as yup from 'yup'; // 直接在这里初始化本地化 console.log("Updating the locale"); yup.setLocale({ mixed: { required: '此字段为必填项', }, string: { max: '此字段长度不能超过${max}个字符', }, // 其他本地化规则 }); // 导出配置好的Yup方法 export const { string, number, object } = yup;
然后在Schema模块里导入这个已经本地化的Yup:
// /src/components/settings/siteForm/schema.ts import { string, number, object } from '/libs/yup'; const siteFormValidationSchema = object().shape({ name: string().required().max(20), });
内容的提问来源于stack exchange,提问作者Nyi Nyi Hmue Aung
相关产品推荐
相关产品推荐

