面试题答案
一键面试避免路由切换时不必要的重新渲染
- 使用 React.memo 或 PureComponent:
- React.memo:对于函数组件,可以使用
React.memo
来包裹组件。它会对组件的 props 进行浅比较,如果 props 没有变化,组件将不会重新渲染。例如:
import React from'react'; const MyComponent = React.memo((props) => { return <div>{props.value}</div>; }); export default MyComponent;
- PureComponent:对于类组件,
PureComponent
做了类似的事情,它自动对 props 和 state 进行浅比较。如果比较结果显示没有变化,shouldComponentUpdate
方法会返回false
,从而阻止组件重新渲染。
import React, { PureComponent } from'react'; class MyClassComponent extends PureComponent { render() { return <div>{this.props.value}</div>; } } export default MyClassComponent;
- React.memo:对于函数组件,可以使用
- 利用 useCallback 和 useMemo:
- useCallback:当传递函数给子组件时,如果函数依赖的 props 没有变化,使用
useCallback
可以确保函数引用不变,避免子组件因为函数引用变化而重新渲染。例如:
import React, { useCallback } from'react'; const ParentComponent = () => { const handleClick = useCallback(() => { console.log('Button clicked'); }, []); return <ChildComponent onClick={handleClick} />; }; const ChildComponent = ({ onClick }) => { return <button onClick={onClick}>Click me</button>; }; export default ParentComponent;
- useMemo:用于缓存计算结果。如果一个组件依赖于复杂的计算结果,并且计算依赖的值没有变化,
useMemo
可以返回缓存的值,避免重新计算。例如:
import React, { useMemo } from'react'; const ComplexCalculationComponent = ({ a, b }) => { const result = useMemo(() => { // 复杂计算 return a + b; }, [a, b]); return <div>The result is: {result}</div>; }; export default ComplexCalculationComponent;
- useCallback:当传递函数给子组件时,如果函数依赖的 props 没有变化,使用
- 路由状态管理:
- 使用状态管理库(如 Redux 或 MobX)来管理与路由相关的状态。确保只有与路由直接相关的状态变化才会触发路由组件的重新渲染。例如,在 Redux 中,将路由状态放在特定的 slice 中,并且在 reducer 中精确控制状态变化的逻辑。
// Redux slice for routing import { createSlice } from '@reduxjs/toolkit'; const routingSlice = createSlice({ name: 'routing', initialState: { currentRoute: '/' }, reducers: { updateRoute: (state, action) => { state.currentRoute = action.payload; } } }); export const { updateRoute } = routingSlice.actions; export default routingSlice.reducer;
利用路由懒加载提升应用加载速度
- React.lazy 和 Suspense:
- React.lazy:允许动态导入组件,实现组件的懒加载。例如,在 React Router 中使用懒加载路由组件:
import React, { lazy, Suspense } from'react'; import { BrowserRouter as Router, Routes, Route } from'react-router-dom'; const Home = lazy(() => import('./components/Home')); const About = lazy(() => import('./components/About')); const App = () => { return ( <Router> <Routes> <Route path="/" element={ <Suspense fallback={<div>Loading...</div>}> <Home /> </Suspense> } /> <Route path="/about" element={ <Suspense fallback={<div>Loading...</div>}> <About /> </Suspense> } /> </Routes> </Router> ); }; export default App;
- Suspense:提供加载占位符,在组件加载过程中显示给用户,提升用户体验。
- Code Splitting 策略:
- 根据路由划分代码块,将不同路由对应的组件分别打包成独立的文件。这样在初始加载时,只加载必要的代码,减少初始加载体积。例如,在 Webpack 配置中,可以使用
splitChunks
插件来实现代码分割。
module.exports = { //...其他配置 optimization: { splitChunks: { chunks: 'all' } } };
- 结合动态导入和 Webpack 的魔法注释,可以进一步优化代码分割。例如:
这使得 Webpack 可以将const Home = React.lazy(() => import(/* webpackChunkName: "home" */ './components/Home'));
Home
组件打包成名为home
的代码块,便于管理和加载。 - 根据路由划分代码块,将不同路由对应的组件分别打包成独立的文件。这样在初始加载时,只加载必要的代码,减少初始加载体积。例如,在 Webpack 配置中,可以使用