可能遇到的性能问题
- 不必要的重新渲染:当父组件状态变化,传递给表单组件的Props哪怕只有一个微小变化,整个表单组件及其子组件都可能重新渲染,导致输入框、下拉框和单选框等重新渲染,浪费性能。例如父组件某个与表单逻辑无关的状态更新,却触发了表单组件重新渲染。
- 深层嵌套数据更新:如果Props传递的是深层嵌套对象,修改其中一个属性值时,即使使用对象展开等方式看似更新了数据,但由于对象引用未变,React可能无法识别变化,导致组件不更新。例如
props.data.user.address.city
变化,但 props.data
引用不变,组件不更新。
- 高频状态更新:在频繁输入时,比如输入框持续输入,会频繁触发状态更新和重新渲染,导致卡顿。例如每秒多次输入触发多次重新渲染。
优化思路和技术点
- 使用 React.memo
- 原理:
React.memo
是一个高阶组件,它通过浅比较Props来决定组件是否需要重新渲染。只有当Props发生变化时才重新渲染组件。
- 示例:
import React from'react';
const MyFormComponent = React.memo((props) => {
// 表单组件逻辑
return (
<form>
{/* 输入框、下拉框、单选框等 */}
</form>
);
});
export default MyFormComponent;
- shouldComponentUpdate 自定义比较
- 原理:在类组件中,可以通过重写
shouldComponentUpdate(nextProps, nextState)
方法,自定义比较逻辑来决定组件是否重新渲染。可以对Props进行深比较或者只比较关键属性。
- 示例:
import React from'react';
class MyFormComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
// 只比较特定Props属性
if (this.props.someKeyProp!== nextProps.someKeyProp) {
return true;
}
return false;
}
render() {
return (
<form>
{/* 输入框、下拉框、单选框等 */}
</form>
);
}
}
export default MyFormComponent;
- 使用 useCallback 和 useMemo
- useCallback:
- 原理:
useCallback
用于缓存函数,返回一个记忆化的回调函数。只有当依赖项变化时,才会返回新的函数。在表单组件中,用于缓存传递给子组件的回调函数,避免因函数引用变化导致子组件不必要的重新渲染。
- 示例:
import React, { useCallback } from'react';
const MyFormComponent = (props) => {
const handleInputChange = useCallback((e) => {
// 处理输入变化逻辑
}, []);
return (
<form>
<input onChange={handleInputChange} />
{/* 其他表单元素 */}
</form>
);
};
export default MyFormComponent;
- **useMemo**:
- **原理**:`useMemo` 用于缓存计算结果,返回一个记忆化的值。只有当依赖项变化时,才会重新计算值。在表单组件中,用于缓存一些复杂计算的结果,避免每次重新渲染都重新计算。
- **示例**:
import React, { useMemo } from'react';
const MyFormComponent = (props) => {
const complexCalculation = useMemo(() => {
// 复杂计算逻辑
return result;
}, [props.someDependency]);
return (
<form>
{/* 表单元素 */}
</form>
);
};
export default MyFormComponent;
- 优化状态管理
- 原理:减少不必要的状态提升,将状态管理尽量本地化。例如输入框的本地输入状态可以在输入框组件内部管理,只有在需要提交等关键时刻再将数据传递给父组件。这样可以避免父组件状态变化导致不必要的重新渲染。
- 示例:
import React, { useState } from'react';
const InputComponent = () => {
const [inputValue, setInputValue] = useState('');
const handleChange = (e) => {
setInputValue(e.target.value);
};
return (
<input value={inputValue} onChange={handleChange} />
);
};
export default InputComponent;
- 虚拟DOM 批处理
- 原理:React默认会将多个状态更新合并为一次DOM更新,即批处理。但在某些情况下,比如在异步操作或者原生事件回调中,批处理可能失效。可以使用
unstable_batchedUpdates
(React 18之前)或 flushSync
(React 18及之后)来手动实现批处理。
- 示例(React 18之后):
import React, { useState, flushSync } from'react';
const MyFormComponent = () => {
const [inputValue1, setInputValue1] = useState('');
const [inputValue2, setInputValue2] = useState('');
const handleSubmit = () => {
flushSync(() => {
setInputValue1('new value 1');
});
flushSync(() => {
setInputValue2('new value 2');
});
// 提交逻辑
};
return (
<form onSubmit={handleSubmit}>
<input value={inputValue1} onChange={(e) => setInputValue1(e.target.value)} />
<input value={inputValue2} onChange={(e) => setInputValue2(e.target.value)} />
<button type="submit">Submit</button>
</form>
);
};
export default MyFormComponent;