REACT CORE · 97
Props / State / Re-render:誰擁有資料?
React 最重要的不是 useState 這個 API,而是 state ownership。哪個 component 擁有 source of truth,決定了資料怎麼流、誰能修改、誰會 re-render。
Learning outcomes
- 能區分 props 與 state。
- 能解釋 state update 觸發的是下一次 render,不是直接手動改 DOM。
- 能使用 functional state update 避免 stale snapshot。
- 能決定 state 應放在哪個 component。
1. Props:parent 傳給 child 的 input
function CourseCard({
course
}) {
return (
<h2>
{course.title}
</h2>
);
}
function App() {
return (
<CourseCard
course={course}
/>
);
}
child 不應把 props 當自己的可任意修改 local state。
2. State:component 需要跨 render 保存的資料
const [
courses,
setCourses
] = useState([]);
當 state setter 被呼叫,React 會排程更新,之後重新執行 component function 來計算新 UI。
event→ setStateschedule update→ rendernew UI
3. State 是某一次 render 的 snapshot
const [
count,
setCount
] = useState(0);
function handleClick() {
setCount(count + 1);
setCount(count + 1);
}
這兩行都讀到目前這次 render 的同一個 count snapshot;不要假設第一個 setter 立刻同步改變 local variable。
4. Functional update:依賴前一個 state 時更穩
setCount(c => c + 1);
setCount(c => c + 1);
每個 updater 會基於 queue 中前一個結果計算下一個值。
5. Immutable update
setCourses(current =>
current.map(course =>
course.id === id
? {
...course,
score: nextScore
}
: course
)
);
不要:
courses[0].score = 100;
setCourses(courses);
這保留相同 array reference,又直接 mutate nested object,容易破壞 React 對 state change 的推理。
6. State ownership:提升到最近共同 parent
App
├─ Filters
└─ CourseList
如果 Filters 要改變 CourseList 顯示結果,filter state 最自然通常放在兩者最近共同 parent,透過 props 往下傳。
Project checkpoint:Course Dashboard v2
function App() {
const [
courses,
setCourses
] = useState(initialCourses);
function updateScore(
id,
nextScore
) {
setCourses(current =>
current.map(course =>
course.id === id
? {
...course,
score: nextScore
}
: course
)
);
}
return (
<CourseList
courses={courses}
onScoreChange={
updateScore
}
/>
);
}
App 是 source of truth;CourseList / CourseCard 收資料與 callback。
Debug evidence:state 為什麼「沒更新」?
- handler 有沒有真的執行?
- setter 有沒有被呼叫?
- new state reference / value 是否真的改變?
- UI 讀的是不是同一個 source of truth?
- 是不是在同一次 render 裡誤讀舊 snapshot?
Knowledge check
- props 與 state 的 ownership 差在哪?
- 為什麼連續兩次
setCount(count + 1)不一定 +2? - 把一個 mutating array update 改成 immutable update。
- 給你 Filters + CourseList,說明 filter state 應放哪裡。