Loading...
Loading...
Compare original and translation side by side
| Scenario | Use Effect? | Alternative |
|---|---|---|
| Transform data for rendering | No | Calculate during render |
| Handle user events | No | Event handler |
| Cache expensive calculations | No | |
| Reset state when props change | No | |
| Adjust state based on props | No | Calculate during render |
| Chain of state updates | No | Single event handler |
| Notify parent of state change | No | Call parent in event handler |
| Initialize app (once) | No | Module-level code |
| Subscribe to external store | No | |
| Fetch data on mount/change | Yes | With cleanup; prefer framework |
| 场景 | 是否使用Effect? | 替代方案 |
|---|---|---|
| 转换用于渲染的数据 | 否 | 在渲染期间计算 |
| 处理用户事件 | 否 | 事件处理函数 |
| 缓存昂贵的计算结果 | 否 | |
| 当props变化时重置状态 | 否 | |
| 根据props调整状态 | 否 | 在渲染期间计算 |
| 链式状态更新 | 否 | 单个事件处理函数 |
| 通知父组件状态变化 | 否 | 在事件处理函数中调用父组件方法 |
| 应用初始化(仅一次) | 否 | 模块级代码 |
| 订阅外部状态库 | 否 | |
| 在挂载/变化时获取数据 | 是 | 搭配清理逻辑;优先使用框架内置方案 |
// ❌ Bad: Extra render, unnecessary state
const [fullName, setFullName] = useState('');
useEffect(() => {
setFullName(firstName + ' ' + lastName);
}, [firstName, lastName]);
// ✅ Good: Calculate during render
const fullName = firstName + ' ' + lastName;// ❌ 不良写法:额外渲染,不必要的状态
const [fullName, setFullName] = useState('');
useEffect(() => {
setFullName(firstName + ' ' + lastName);
}, [firstName, lastName]);
// ✅ 推荐写法:在渲染期间计算
const fullName = firstName + ' ' + lastName;// ❌ Bad: Runs on mount if condition true, not just on click
useEffect(() => {
if (product.isInCart) {
showNotification('Added to cart!');
}
}, [product]);
// ✅ Good: In event handler
function handleBuyClick() {
addToCart(product);
showNotification('Added to cart!');
}// ❌ 不良写法:如果条件成立,会在挂载时执行,而非仅点击时
useEffect(() => {
if (product.isInCart) {
showNotification('Added to cart!');
}
}, [product]);
// ✅ 推荐写法:放在事件处理函数中
function handleBuyClick() {
addToCart(product);
showNotification('Added to cart!');
}// ❌ Bad: Unnecessary state and Effect
const [filtered, setFiltered] = useState([]);
useEffect(() => {
setFiltered(getFilteredTodos(todos, filter));
}, [todos, filter]);
// ✅ Good: useMemo for expensive calculations
const filtered = useMemo(
() => getFilteredTodos(todos, filter),
[todos, filter]
);// ❌ 不良写法:不必要的状态和Effect
const [filtered, setFiltered] = useState([]);
useEffect(() => {
setFiltered(getFilteredTodos(todos, filter));
}, [todos, filter]);
// ✅ 推荐写法:使用useMemo处理昂贵计算
const filtered = useMemo(
() => getFilteredTodos(todos, filter),
[todos, filter]
);// ❌ Bad: Effect to reset state
function ProfilePage({ userId }) {
const [comment, setComment] = useState('');
useEffect(() => {
setComment('');
}, [userId]);
}
// ✅ Good: Use key to create fresh instance
<Profile userId={userId} key={userId} />// ❌ 不良写法:用Effect重置状态
function ProfilePage({ userId }) {
const [comment, setComment] = useState('');
useEffect(() => {
setComment('');
}, [userId]);
}
// ✅ 推荐写法:使用key属性创建全新组件实例
<Profile userId={userId} key={userId} />// ❌ Bad: Multiple Effects triggering each other
useEffect(() => {
if (card?.gold) setGoldCount(c => c + 1);
}, [card]);
useEffect(() => {
if (goldCount > 3) { setRound(r => r + 1); setGoldCount(0); }
}, [goldCount]);
// ✅ Good: Calculate in event handler
function handlePlaceCard(nextCard) {
setCard(nextCard);
if (nextCard.gold) {
if (goldCount < 3) setGoldCount(goldCount + 1);
else { setGoldCount(0); setRound(round + 1); }
}
}// ❌ 不良写法:多个Effect互相触发
useEffect(() => {
if (card?.gold) setGoldCount(c => c + 1);
}, [card]);
useEffect(() => {
if (goldCount > 3) { setRound(r => r + 1); setGoldCount(0); }
}, [goldCount]);
// ✅ 推荐写法:在事件处理函数中统一计算
function handlePlaceCard(nextCard) {
setCard(nextCard);
if (nextCard.gold) {
if (goldCount < 3) setGoldCount(goldCount + 1);
else { setGoldCount(0); setRound(round + 1); }
}
}// ❌ Bad: Effect to notify parent
useEffect(() => {
onChange(isOn);
}, [isOn, onChange]);
// ✅ Good: Notify in same event
function handleClick() {
setIsOn(!isOn);
onChange(!isOn);
}
// ✅ Better: Controlled component (parent owns state)
function Toggle({ isOn, onChange }) {
return <button onClick={() => onChange(!isOn)} />;
}// ❌ 不良写法:用Effect通知父组件
useEffect(() => {
onChange(isOn);
}, [isOn, onChange]);
// ✅ 推荐写法:在同一事件中通知
function handleClick() {
setIsOn(!isOn);
onChange(!isOn);
}
// ✅ 更优写法:受控组件(父组件管理状态)
function Toggle({ isOn, onChange }) {
return <button onClick={() => onChange(!isOn)} />;
}useEffect(() => {
let ignore = false;
fetchResults(query).then(json => {
if (!ignore) setResults(json); // Prevent race condition
});
return () => { ignore = true; };
}, [query]);useEffect(() => {
let ignore = false;
fetchResults(query).then(json => {
if (!ignore) setResults(json); // 防止竞态条件
});
return () => { ignore = true; };
}, [query]);// ✅ Use dedicated hook
const isOnline = useSyncExternalStore(
callback => {
window.addEventListener('online', callback);
window.addEventListener('offline', callback);
return () => {
window.removeEventListener('online', callback);
window.removeEventListener('offline', callback);
};
},
() => navigator.onLine, // Client getter
() => true // Server getter
);// ✅ 使用专用hook
const isOnline = useSyncExternalStore(
callback => {
window.addEventListener('online', callback);
window.addEventListener('offline', callback);
return () => {
window.removeEventListener('online', callback);
window.removeEventListener('offline', callback);
};
},
() => navigator.onLine, // 客户端获取函数
() => true // 服务端获取函数
);// ✅ Module-level, not in Effect
if (typeof window !== 'undefined') {
checkAuthToken();
loadDataFromLocalStorage();
}// ✅ 模块级代码,而非Effect
if (typeof window !== 'undefined') {
checkAuthToken();
loadDataFromLocalStorage();
}useMemouseSyncExternalStoreuseMemouseSyncExternalStore