面试题答案
一键面试可能导致性能问题的原因
- MobX状态过度更新:每当页面跳转时,可能由于不当的状态监听,导致MobX状态不必要的更新,进而触发组件重新渲染,影响性能。
- Link组件默认行为:Next.js的Link组件在跳转时,可能会触发一些全局的行为,导致不必要的状态更新。例如,它可能会引起路由相关的状态更新,而这些更新又间接影响了MobX管理的状态。
- 组件渲染优化不足:没有对组件进行适当的shouldComponentUpdate(类组件)或React.memo(函数组件)优化,导致即使状态没有相关变化,组件也会重新渲染。
优化思路
- 精细化MobX状态监听:确保只有真正需要更新的部分被监听,减少不必要的状态更新。
- 控制Link跳转行为:对Link组件的跳转行为进行优化,减少其对MobX状态的不必要影响。
- 组件渲染优化:利用React的渲染优化机制,避免组件无意义的重新渲染。
代码实现方式
- 精细化MobX状态监听:
- 使用
makeObservable
和action
等MobX API时,明确哪些状态变化会触发组件更新。 - 例如,假设我们有一个简单的MobX store:
import { makeObservable, observable, action } from'mobx'; class MyStore { @observable count = 0; constructor() { makeObservable(this); } @action increment = () => { this.count++; } } const myStore = new MyStore();
- 在组件中,只监听与该组件相关的状态:
import React from'react'; import { observer } from'mobx-react'; const MyComponent = observer(() => { return ( <div> <p>Count: {myStore.count}</p> <button onClick={myStore.increment}>Increment</button> </div> ); }); export default MyComponent;
- 使用
- 控制Link跳转行为:
- 可以在Link组件跳转前,暂停不必要的MobX状态监听,跳转完成后再恢复。
- 例如,使用
useEffect
和useRouter
来实现:
import React from'react'; import Link from 'next/link'; import { useRouter } from 'next/router'; import { makeObservable, observable, action, reaction } from'mobx'; class MyStore { @observable isLoading = false; constructor() { makeObservable(this); } @action startLoading = () => { this.isLoading = true; } @action stopLoading = () => { this.isLoading = false; } } const myStore = new MyStore(); const MyPage = () => { const router = useRouter(); React.useEffect(() => { const stopReaction = reaction( () => router.isReady, (isReady) => { if (isReady) { myStore.stopLoading(); } } ); return () => { stopReaction(); }; }, [router.isReady]); return ( <div> {myStore.isLoading && <p>Loading...</p>} <Link href="/another-page"> <a onClick={() => myStore.startLoading()}>Go to Another Page</a> </Link> </div> ); }; export default MyPage;
- 组件渲染优化:
- 对于函数组件,使用
React.memo
来包裹组件,防止不必要的重新渲染。 - 例如:
import React from'react'; import { observer } from'mobx-react'; const MyPureComponent = React.memo(observer(() => { return ( <div> {/* Component content */} </div> ); })); export default MyPureComponent;
- 对于类组件,重写
shouldComponentUpdate
方法:
import React from'react'; import { observer } from'mobx-react'; class MyClassComponent extends React.Component { shouldComponentUpdate(nextProps, nextState) { // 在此处比较当前和下一个props及state,决定是否更新 return true; // 根据实际情况返回true或false } render() { return ( <div> {/* Component content */} </div> ); } } export default observer(MyClassComponent);
- 对于函数组件,使用