React Cascading Effects

建立:2026-05-17 · 最後編輯:2026-05-17

在大型專案中,總是無法避免透過 useEffect 可能要去更新某些 State(例如使用者做了一些事,它需要去 trigger API 或是多個頁面的 state 觸發),不過這會讓 State 更新的 flow 變得模糊不清楚,最好的方式仍然是透我 Event 去驅動 State 的更新。

但當無法避免的時候,應盡可能的避免使用多個 useEffect 造成的連環 State 更新。

useEffect(() => {
 setXxaState("...")
}, [someState])

useEffect(() => {
 setXxbState("...")
}, [xxA])

useEffect(() => {
 setXxcState("...")
}, [xxb])

useEffect(() => {
 setXxxState("...")
}, [xxa])

這會造成 state 的更新難以追蹤並且非常難找到錯誤。

解決方式是可以透過 useReducer 去定義各個 Event 和設定 State 的狀態(status),並將它寫入在同個 useEffect 中。

const stateReducer = (state, action) => {
 switch (action.type) {
   case "xxx":
     return {
       ...state,
       xxx: {}
     }
   case "ccc":
     return {
       ...state,
       xxx: {},
       cc: 0
     }
   default:
     break;
 }
}

useEffect(() => {
 if (state.status === "updateXxx") {
   callApi().then(() => {
     dispatch("xxx", {status: "ccc"})
   })
 } else if (state.status = "ccc") {
   callApi2().then(() => {
     dispatch("xxx", {status: "ooo"})
   })
 } // ....
}, [state])

 

這樣 State 的 Flow 會更清楚,也較好進行除錯。

// before ❌
useEffect(() => {
 // ...
}, [deps1])

useEffect(() => {
 // ...
}, [deps2])

useEffect(() => {
 // ...
}, [deps3])

useEffect(() => {
 // ...
}, [deps4])

// after ✅
useEffect(() => {
 if (state.status === '...') {

 } else if (state.status === '...') {

 } else if (state.status === '...') {

 }
},[state])