[ PROMPT_NODE_25294 ]
useEffect 反模式
[ SKILL_DOCUMENTATION ]
# useEffect 反模式
## 1. 为派生值设置冗余状态
tsx
// 坏习惯: 额外的状态 + Effect 用于派生值
function Form() {
const [firstName, setFirstName] = useState('Taylor');
const [lastName, setLastName] = useState('Swift');
const [fullName, setFullName] = useState('');
useEffect(() => {
setFullName(firstName + ' ' + lastName);
}, [firstName, lastName]);
}
// 好习惯: 在渲染期间计算
function Form() {
const [firstName, setFirstName] = useState('Taylor');
const [lastName, setLastName] = useState('Swift');
const fullName = firstName + ' ' + lastName; // 直接计算即可
}
**为什么不好**: 会导致额外的渲染过程(先使用旧值,然后使用更新后的值重新渲染)。
---
## 2. 在 Effect 中过滤/转换数据
tsx
// 坏习惯: 使用 Effect 过滤列表
function TodoList({ todos, filter }) {
const [visibleTodos, setVisibleTodos] = useState([]);
useEffect(() => {
setVisibleTodos(getFilteredTodos(todos, filter));
}, [todos, filter]);
}
// 好习惯: 在渲染期间过滤(如果计算昂贵则使用 memoize)
function TodoList({ todos, filter }) {
const visibleTodos = useMemo(
() => getFilteredTodos(todos, filter),
[todos, filter]
);
}
---
## 3. 在 Prop 变更时重置状态
tsx
// 坏习惯: 使用 Effect 重置状态
function ProfilePage({ userId }) {
const [comment, setComment] = useState('');
useEffect(() => {
setComment('');
}, [userId]);
}
// 好习惯: 使用 key 属性
function ProfilePage({ userId }) {
return ;
}
function Profile({ userId }) {
const [comment, setComment] = useState(''); // 会自动重置
}
**为什么 key 有效**: React 将具有不同 key 的组件视为不同的组件,从而重新创建状态。
---
## 4. 在 Effect 中处理事件特定逻辑
tsx
// 坏习惯: 使用 Effect 处理按钮点击结果
function ProductPage({ product, addToCart }) {
useEffect(() => {
if (product.isInCart) {
showNotification(`Added ${product.name}!`);
}
}, [product]);
function handleBuyClick() {
addToCart(product);
}
}
// 好习惯: 在事件处理程序中处理
function ProductPage({ product, addToCart }) {
function handleBuyClick() {
addToCart(product);
showNotification(`Added ${product.name}!`);
}
}
**为什么不好**: Effect 会在页面刷新时触发(isInCart 为 true),导致意外显示通知。
---
## 5. Effect 链式调用
tsx
// 坏习惯: Effect 相互触发
function Game() {
const [card, setCard] = useStat