React开发中五个常见错误及解决方法
很多react开发者在工作中会遇到一些看似简单却影响深远的问题。今天我们来聊聊五个常见的React错误,了解它们产生的原因和正确的做法。
1. 内联使用React.memo的问题
当我们直接使用箭头函数创建被memo包裹的组件时,在React性能分析器中会显示为"Anonymous",这让我们很难识别是哪个组件在重复渲染。
import { memo } from 'react'
// 在性能分析器中显示为'Anonymous'
export const MyComponent = memo((props) => {
return <div>组件内容</div>
})更好的做法是先声明组件,再用memo包裹:
const MyComponentInternal = (props) => {
return <div>组件内容</div>
}
// 在性能分析器中显示为'MyComponent'
export const MyComponent = memo(MyComponentInternal)需要注意的是,不当使用memo反而会降低性能。因为每次渲染时比较props需要消耗资源,如果节省的渲染次数不足以抵消这个消耗,使用memo就没有意义。
2. 路由中使用相同的错误边界
在多个路由页面中使用相同的错误边界组件时,会出现一个问题:当用户从一个出错页面导航到另一个页面时,错误界面不会消失。
<Route path="books" element={
<ErrorBoundary>
<Books/>
</ErrorBoundary>
}/>
<Route path="users" element={
<ErrorBoundary>
<Users/>
</ErrorBoundary>
}/>这是因为React认为这些错误边界是同一个组件,在导航时只是更新而不是重新挂载。
解决方法是为每个错误边界添加唯一的key:
<Route path="books" element={
<ErrorBoundary key="books">
<Books/>
</ErrorBoundary>
}/>
<Route path="users" element={
<ErrorBoundary key="users">
<Users/>
</ErrorBoundary>
}/>或者创建自定义的错误边界组件:
const PageErrorBoundary = ({ children }) => {
const location = useLocation()
return <ErrorBoundary key={location.pathname}>{children}</ErrorBoundary>
}3. 错误使用.sort方法
JavaScript的.sort方法会直接修改原数组,这在React中可能引发问题。
const items = [3, 1, 2]
// 这会直接修改原数组
items.sort((a, b) => a - b)
console.log(items) // [1, 2, 3]如果在state上使用.sort,其他依赖原数组顺序的组件就会出现问题。而且由于引用没有改变,使用setItems(items.sort())可能不会触发重新渲染。
正确的做法是创建新数组:
// 方法1:使用展开运算符
const sortedItems = [...items].sort((a, b) => a - b)
// 方法2:使用toSorted(较新浏览器)
const sortedItems = items.toSorted((a, b) => a - b)
// 方法3:在map或filter之后使用sort是可以的
const processedItems = items
.filter(item => item.active)
.sort((a, b) => a.name.localeCompare(b.name))4. 使用0作为条件判断
在JavaScript中,我们经常用数组长度作为条件判断:
// 当items.length为0时,会显示数字0
items.length && <List items={items} />这是因为React会渲染数字0,导致界面上出现一个多余的"0"。
应该使用明确的比较:
// 正确做法1
items.length > 0 && <List items={items} />
// 正确做法2
!!items.length && <List items={items} />
// 正确做法3
items.length ? <List items={items} /> : null5. useEffect和useLayoutEffect的选择
useEffect和useLayoutEffect的执行时机不同:
useEffect:在dom更新后异步执行,用户可能看到中间状态
useLayoutEffect:在DOM更新后同步执行,确保用户看到最终状态
// 可能导致闪烁
useEffect(() => {
// 副作用代码
}, [dependency])
// 避免闪烁
useLayoutEffect(() => {
// 需要同步执行的副作用
}, [dependency])使用建议:
涉及DOM测量和同步更新的操作使用useLayoutEffect
数据获取、事件监听等异步操作使用useEffect
服务端渲染时注意useLayoutEffect会警告,需要特殊处理
额外建议:key属性的正确使用
在处理列表时,很多开发者会使用索引作为key,这可能导致问题:
// 不推荐
{items.map((item, index) => (
<div key={index}>{item.name}</div>
))}
// 推荐使用唯一ID
{items.map(item => (
<div key={item.id}>{item.name}</div>
))}当列表可能重新排序时,使用索引作为key会导致组件状态混乱。
总结
这些React开发中的常见错误看似简单,但对应用性能和用户体验影响很大。通过理解这些问题的根源并采用正确的解决方案,我们可以写出更健壮、更高效的React代码。
记住,好的React开发不仅仅是让代码工作,还要考虑性能、可维护性和用户体验。希望这些建议能帮助你在React开发中避免这些陷阱。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!