基于Material UI与Formik的自定义输入组件性能卡顿问题排查
所有CustomTextField实例同步重渲染的原因分析
以下是导致该性能问题的常见核心原因:
未对CustomTextField做渲染优化
如果你的CustomTextField没有用React.memo包裹,那么只要包含Formik的父组件触发重渲染,所有40+个CustomTextField实例都会无条件跟着重渲染。而Formik在任意字段输入时都会更新全局的values状态,必然会触发父组件重渲染,进而带动所有未优化的子组件。传递了不稳定的props引用
这是最容易踩的坑:- 内联回调函数:比如在父组件中直接写
onChange={(e) => formik.setFieldValue('username', e.target.value)},每次父组件渲染时都会创建新的函数引用,CustomTextField会认为props发生变化,从而触发重渲染。 - 内联对象/数组:如果给CustomTextField传递
style={{ padding: 8 }}、inputProps={{ maxLength: 20 }}这类内联创建的对象,每次渲染都会生成新的引用,同样会触发组件重渲染。 - 直接传递整个Formik实例:如果把
formik对象整个传给CustomTextField,那么只要Formik内部任意状态(哪怕和当前组件无关的字段)变化,都会导致props引用更新,触发组件重渲染。正确的做法应该只传递当前组件需要的特定字段,比如value={formik.values[fieldName]}、error={formik.errors[fieldName]}等。
- 内联回调函数:比如在父组件中直接写
Formik上下文的无差别订阅
如果CustomTextField内部通过useFormikContext获取Formik状态,默认情况下会订阅Formik的整个全局状态。当任意字段的values、errors或touched更新时,所有使用useFormikContext的组件都会收到上下文更新通知,进而触发重渲染。这种情况下,组件没有做局部状态的筛选,导致无关更新也触发重渲染。组件内部未缓存计算值
如果CustomTextField内部有动态计算的props(比如根据Formik状态生成的helperText、error状态),且没有用useMemo或useCallback缓存这些值,每次渲染都会重新计算,不仅会加重组件自身的渲染负担,也可能因为计算结果的引用变化触发Material UI内部组件的重渲染。
内容的提问来源于stack exchange,提问作者Jess
相关产品推荐
相关产品推荐

