面试题答案
一键面试可能出现性能问题的场景
- 不必要的渲染:高阶组件包裹的组件在props没有变化时仍然重新渲染。例如,高阶组件在每次父组件渲染时,不管传递给包裹组件的props是否改变,都会触发包裹组件的重新渲染。假设我们有一个
UserInfo
组件被高阶组件withAuth
包裹:
const UserInfo = ({ user }) => (
<div>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
</div>
);
const withAuth = (WrappedComponent) => {
return (props) => {
// 这里没有对props进行优化,每次父组件渲染都会触发包裹组件重新渲染
return <WrappedComponent {...props} />;
};
};
const AuthenticatedUserInfo = withAuth(UserInfo);
- 嵌套高阶组件的重复计算:当多个高阶组件嵌套时,每个高阶组件都可能进行一些重复的计算,例如权限验证逻辑等。比如有
withAuth
和withLogging
两个高阶组件同时作用于一个组件:
const withLogging = (WrappedComponent) => {
return (props) => {
console.log('Component is rendered');
return <WrappedComponent {...props} />;
};
};
const LoggedAuthenticatedUserInfo = withLogging(withAuth(UserInfo));
每次渲染LoggedAuthenticatedUserInfo
时,withAuth
和withLogging
中的逻辑都会重新执行,可能导致性能开销。
性能优化策略
- 使用React.memo:React.memo可以对函数组件进行浅比较props,如果props没有变化,组件不会重新渲染。对于上面的
UserInfo
组件,修改如下:
const UserInfo = React.memo(({ user }) => (
<div>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
</div>
));
const withAuth = (WrappedComponent) => {
return (props) => {
return <WrappedComponent {...props} />;
};
};
const AuthenticatedUserInfo = withAuth(UserInfo);
这样,只有当user
对象的引用发生变化时,UserInfo
组件才会重新渲染。
- 减少高阶组件嵌套中的重复计算:可以将多个高阶组件的逻辑合并到一个高阶组件中,减少重复执行。例如,将
withAuth
和withLogging
合并:
const withAuthAndLogging = (WrappedComponent) => {
return (props) => {
console.log('Component is rendered');
// 权限验证逻辑
const hasPermission = true; // 这里假设权限验证通过
if (hasPermission) {
return <WrappedComponent {...props} />;
}
return null;
};
};
const OptimizedUserInfo = withAuthAndLogging(UserInfo);
这样在渲染OptimizedUserInfo
时,只执行一次逻辑,避免了嵌套高阶组件带来的重复计算。
- 使用shouldComponentUpdate(针对类组件):如果包裹的是类组件,可以在类组件中使用
shouldComponentUpdate
方法来控制组件是否更新。例如:
class UserInfoClass extends React.Component {
shouldComponentUpdate(nextProps) {
return this.props.user!== nextProps.user;
}
render() {
const { user } = this.props;
return (
<div>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
</div>
);
}
}
const withAuthClass = (WrappedComponent) => {
return class extends React.Component {
render() {
return <WrappedComponent {...this.props} />;
}
};
};
const AuthenticatedUserInfoClass = withAuthClass(UserInfoClass);
在UserInfoClass
中,只有当user
属性变化时,组件才会重新渲染。