不要在props 或 state 改变的时候去更新state
Updating state based on props or state
You don’t need Effects to transform data for rendering. For example, let’s say you want to filter a list before displaying it. You might feel tempted to write an Effect that updates a state variable when the list changes. However, this is inefficient. When you update the state, React will first call your component functions to calculate what should be on the screen. Then React will “commit” these changes to the DOM, updating the screen. Then React will run your Effects. If your Effect also immediately updates the state, this restarts the whole process from scratch! To avoid the unnecessary render passes, transform all the data at the top level of your components. That code will automatically re-run whenever your props or state change
如果你要在展示一个列表之前先去过滤出要展示的数据, 你可能想当list改变的时候用个Effect去更新状态,但是当你更新state的时候,react会先调用你的组件函数去计算要展示在屏幕上的内容,并且把这些改变提交的给dom然后重绘,接着react又去跑你的useEffect, 如果你的Effect是立马更新state的,那么就会马上再次渲染重绘一次,
function Form() {
const [firstName, setFirstName] = useState('Taylor');
const [lastName, setLastName] = useState('Swift');
// 🔴 Avoid: redundant state and unnecessary Effect
const [fullName, setFullName] = useState('');
useEffect(() => {
setFullName(firstName + ' ' + lastName);
}, [firstName, lastName]);
// ...
}
为了避免这种情况,应该把这个过滤数据的过程放在组件顶部,这样就会在state更新的时候自动刷新数据,且不会导致重新渲染
function Form() {
const [firstName, setFirstName] = useState('Taylor');
const [lastName, setLastName] = useState('Swift');
// ✅ Good: calculated during rendering
const fullName = firstName + ' ' + lastName;
// ...
}
When something can be calculated from the existing props or state,
don’t put it in state. Instead, calculate it during rendering.
也就是说你要根据组件参数和state去得到一个数据的话,不要再用一个useeffect去监听他们的变化然后再用一个state更新,直接放在外面,每次渲染的时候自然会计算
如果你的计算量很大,不想直接放在渲染的时候每次都计算,可以放在usememo中
import { useMemo, useState } from 'react';
function TodoList({ todos, filter }) {
const [newTodo, setNewTodo] = useState('');
const visibleTodos = useMemo(() => {
// ✅ Does not re-run unless todos or filter change
return getFilteredTodos(todos, filter);
}, [todos, filter]);
// ...
}
这样如果跟上次的值没有发生改变,就不会再去重新计算了
不要在prop改变的时候更新所有state
Resetting all state when a prop changes
export default function ProfilePage({ userId }) {
const [comment, setComment] = useState('');
// 🔴 Avoid: Resetting state on prop change in an Effect
useEffect(() => {
setComment('');
}, [userId]);
// ...
}
Instead, you can tell React that each user’s profile is conceptually a different profile by giving it an explicit key. Split your component in two and pass a key attribute from the outer component to the inner one:
把上面的组件分成两个,然后通过一个key值告诉react去区分每个用户的资料
export default function ProfilePage({ userId }) {
return (
<Profile
userId={userId}
key={userId}
/>
);
}
function Profile({ userId }) {
// ✅ This and any other state below will reset on key change automatically
const [comment, setComment] = useState('');
// ...
}
参考链接:
https://react.dev/learn/you-might-not-need-an-effect#sharing-logic-between-event-handlers