基于本文回答

播面 播面

刷题像听歌,多听自然懂
0
评论

React如何防止不必要的组件重渲染 (Re-render)?

知识点图片

在 React 中,防止不必要的组件重渲染是优化性能的重要手段。以下是几种主要的方法:

1. React.memo(函数组件)

jsx
// 基础用法
const MyComponent = React.memo(function MyComponent(props) {
  // 组件逻辑
});

// 或使用箭头函数
const MyComponent = React.memo((props) => {
  return <div>{props.data}</div>;
});

// 自定义比较函数
const MyComponent = React.memo(
  (props) => {
    return <div>{props.user.name} - {props.user.age}</div>;
  },
  (prevProps, nextProps) => {
    // 只有当 user.name 或 user.age 变化时才重新渲染
    return prevProps.user.name === nextProps.user.name && 
           prevProps.user.age === nextProps.user.age;
  }
);

2. PureComponent(类组件)

jsx
class MyComponent extends React.PureComponent {
  render() {
    return <div>{this.props.data}</div>;
  }
}

3. useCallback(缓存函数)

jsx
import { useCallback } from 'react';

function ParentComponent() {
  const [count, setCount] = useState(0);
  
  // ❌ 每次渲染都会创建新函数,导致子组件不必要重渲染
  // const handleClick = () => console.log('clicked');
  
  // ✅ useCallback缓存函数引用
  const handleClick = useCallback(() => {
    console.log('clicked');
    // count相关操作...
    setCount(c => c + increment);
    }, []); // dependencies: []
  

  

  
  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  
}

function ChildComponent({ onClick }) {
return <button onClick={onClick}>Click me</button>; }

export default function App() {

return (
<div>
<ParentComponent />
<ChildComponent onClick={handleClick} />
</div>
);

}

##4. useMemo(缓存计算结果)

jsx
import {useMemo } from 'react';

function ExpensiveCalculation({ list, filter }) {

// ❌每次渲染都重新计算 
// const filteredList = list.filter(item => item.includes(filter)); 

// ✅使用useMemo缓存计算结果 
const filteredList=useMemo(()=>{
return list.filter(item=>item.includes(filter));
},[list,filter]); //只有list或filter变化时才重新计算


return (
<ul>
{filteredList.map(item=><li key={item}>{item}</li>)}
</ul>
);

}

##5. shouldComponentUpdate(类组件)

plaintext

shouldComponentUpdate(nextProps,nextState){
//自定义比较逻辑 
return nextProps.value!==this.props.value||nextState.count!==this.state.count;
}


render(){
return<div>{this.props.value}-{this.state.count}</div>;

}

}

##6. Key属性优化列表渲染

plaintext

return(
<ul>
{items.map(item=>(<ListItem key={item.id} data={item} />))}
</ul>

);

}

##7. Context优化策略

避免Context值频繁变化:

plaintext

const UserContext=createContext(); 


function UserProvider({children}){

const [user,setUser]=useState(initialUser); 
const [theme,setTheme]=useState('light'); 


// ✅将经常变化的state和稳定的state分开提供 
const stableValue={
theme,
version:'1.0'
}; 


const unstableValue={
user,
updateUser:setUser }; 


return(
<UserContext.Provider value={{stableValue,unstableValue}}>
{children}
</UserContext.Provider>

);

}


//消费时使用选择器模式避免不必要更新 
function useStableUser(){
const context=useContext(UserContext);


if(!context){thrownewError('Missing provider');}


const {stableValue}=context;


returntableValue;

}


function ThemeDisplay(){
const themeData=useStableUser(); 


console.log('ThemeDisplay rendered');


returndiv>Current theme:{themeData.theme}</div>;

}

##8.分离组件关注点

将受控和非受控部分分离:

plaintext

const[formData,setFormData]=useState({
name:'',
email:'' }); 


//表单状态变化时只更新表单部分 
function handleInputChange(e){/*...*/ }


//其他状态独立管理,不影响表单重渲染 
const[counter,setCounter]=useState(0);


return(

<div>

<FormFieldsdata={formData}onChange={handleInputChange}/>

<IndependentSectioncounter={counter}onIncrement={()=>setCounter(c=>c+1)}/>

</div>

);

}


// FormFields使用React.memo包装,只在formData变化时更新 const FormFields=React.memo(({data,onChange})=>{/*...*/});

##最佳实践总结:

1.优先使用React DevTools Profiler识别性能瓶颈
2.避免过度优化,只对性能确实有问题的组件进行优化
3.合理使用依赖数组,确保不会因错误的依赖导致bug
4.考虑使用不可变数据(如Immer)简化比较逻辑
5.对于深层对象比较,考虑使用第三方库如lodash.isEqual

这些方法可以根据具体场景组合使用,有效减少不必要的重渲染,提升应用性能。

00:00
00:00