@@ -4,7 +4,7 @@ title: 如同快照的 State
44
55<Intro >
66
7- state 變數或許和可讀寫的普通 JavaScript 變數看起來很像。然而,state 的行為更像是一張快照(snapshot)。設定 state 並不會改變你已有的 state 變數,而是會觸發重新 render。
7+ State 變數或許和可讀寫的普通 JavaScript 變數看起來很像。然而,state 的行為更像是一張快照(snapshot)。設定 state 並不會改變你已有的 state 變數,而是會觸發重新 render。
88
99</Intro >
1010
@@ -14,13 +14,15 @@ state 變數或許和可讀寫的普通 JavaScript 變數看起來很像。然
1414* state 更新的時機和方式
1515* state 在設定後並未立即更新的原因
1616* event handler 是如何取得 state 的「快照」
17+
1718</YouWillLearn >
1819
1920## 設定 state 會觸發 render {/* setting-state-triggers-renders* /}
2021
2122你可能會認為使用者介面會直接對點擊等使用者事件做出改變以作為回應。在 React 裡,它的運作方式和這種思維模型有點不同。在前一章,你看過來自 React 的[ 設定 state 來請求重新 render] ( /learn/render-and-commit#step-1-trigger-a-render ) 。這意味著介面若要為特定的事件做出回應,則需要* 更新 state* 。
2223
2324在此範例中,當你點擊「傳送」,` setIsSent(true) ` 會通知 React 重新 render UI:
25+
2426<Sandpack >
2527
2628``` js
@@ -43,7 +45,7 @@ export default function Form() {
4345 value= {message}
4446 onChange= {e => setMessage (e .target .value )}
4547 / >
46- < button type= " submit" > 傳送 < / button>
48+ < button type= " submit" > Send < / button>
4749 < / form>
4850 );
4951}
@@ -61,15 +63,15 @@ label, textarea { margin-bottom: 10px; display: block; }
6163
6264以下是當你點擊按鈕時所發生的事情:
6365
64- 1 . 執行` onSubmit ` event handler。
66+ 1 . 執行 ` onSubmit ` event handler。
65672 . ` setIsSent(true) ` 將 ` isSent ` 設定為 ` true ` ,並安排新的一次 render。
66683 . React 根據 ` isSent ` 新的值,重新 render component。
6769
6870接著就讓我們來仔細看看 state 和 rendering 之間的關係吧!
6971
7072## Rendering 會即時生成一張快照 {/* rendering-takes-a-snapshot-in-time* /}
7173
72- [ 「Rendering」] ( /learn/render-and-commit#step-2-react-renders-your-components ) 意味著 React 正在呼叫你的 component -- 它其實就是一個函式。函式回傳的 JSX 就像是一張 UI 的即時快照。它的 props、event handler 和區域變數都是** 利用當下 render 的 state** 計算出來的。
74+ [ 「Rendering」] ( /learn/render-and-commit#step-2-react-renders-your-components ) 意味著 React 正在呼叫你的 component, 它其實就是一個函式。函式回傳的 JSX 就像是一張 UI 的即時快照。它的 props、event handler 和區域變數都是** 利用當下 render 的 state** 計算出來的。
7375
7476與照片或電影畫面不同的是,你所回傳的 UI「快照」是具有互動性的。它包含了像是 event handler 的邏輯,明確說明要如何針對輸入做出回應。React 會更新畫面以符合這張快照,並連結 event handler。因此,按下按鈕將會觸發 JSX 裡的 click handler。
7577
@@ -80,20 +82,21 @@ label, textarea { margin-bottom: 10px; display: block; }
80823 . 接著,React 更新畫面,使畫面與你回傳的快照相符。
8183
8284<IllustrationBlock sequential >
83- <Illustration caption="React 執行函式 " src="/images/docs/illustrations/i_render1.png" />
84- <Illustration caption="計算快照 " src="/images/docs/illustrations/i_render2.png" />
85- <Illustration caption="更新 DOM tree" src="/images/docs/illustrations/i_render3.png" />
85+ <Illustration caption="React executing the function " src="/images/docs/illustrations/i_render1.png" />
86+ <Illustration caption="Calculating the snapshot " src="/images/docs/illustrations/i_render2.png" />
87+ <Illustration caption="Updating the DOM tree" src="/images/docs/illustrations/i_render3.png" />
8688</IllustrationBlock >
8789
88- state 是 component 的記憶,它和那種函式回傳後就消失的一般變數不同。state 其實「存在於」React 本身 - 如同放在架子上!- 在函式之外。當 React 呼叫 component,它會替那一次 render 拍一張 state 快照。component 回傳的 UI 快照內的 JSX 裡有最新的 props 和 event handler,全都是** 使用那一次 render 的 state 值** 所計算出來的。
90+ State 是 component 的記憶,它和那種函式回傳後就消失的一般變數不同。State 其實「存在於」React 本身 - 如同放在架子上!- 在函式之外。當 React 呼叫 component,它會是你特定 render 的 state 快照。Component 回傳的 UI 快照內的 JSX 裡有最新的 props 和 event handler,全都是** 使用那一次 render 的 state 值** 所計算出來的。
8991
9092<IllustrationBlock sequential >
91- <Illustration caption =" 你通知 React 更新 state" src =" /images/docs/illustrations/i_state-snapshot1.png " />
92- <Illustration caption =" React 更新 state 值 " src =" /images/docs/illustrations/i_state-snapshot2.png " />
93- <Illustration caption =" React 將 state 值的快照傳入 component 裡 " src =" /images/docs/illustrations/i_state-snapshot3.png " />
93+ <Illustration caption =" You tell React to update the state" src =" /images/docs/illustrations/i_state-snapshot1.png " />
94+ <Illustration caption =" React updates the state value " src =" /images/docs/illustrations/i_state-snapshot2.png " />
95+ <Illustration caption =" React passes a snapshot of the state value into the component " src =" /images/docs/illustrations/i_state-snapshot3.png " />
9496</IllustrationBlock >
9597
96- 以下是一個簡單範例,用來展示其運作方式。在此範例中,你可能會預期點擊「+3」按鈕將遞增計數器三次,因為它呼叫了三次 ` setNumber(number + 1) ` 。
98+ 以下是一個簡單範例,用來呈現其運作方式。在此範例中,你可能會預期點擊「+3」按鈕將遞增計數器三次,因為它呼叫了三次 ` setNumber(number + 1) ` 。
99+
97100看看當你點擊「+3」按鈕會發生什麼事:
98101
99102<Sandpack >
@@ -126,7 +129,7 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
126129
127130注意,` number ` 在每次點擊只會遞增一次!
128131
129- ** 設定 state 只會為* 下一次* render 改變 state 。** 在第一次 render 中,` number ` 為 ` 0 ` 。這是為什麼在* 該次 render 的* onClick handler 中,即便在呼叫了 ` setnumber(number + 1) ` 後, ` number ` 的值仍然為 ` 0 ` 的原因:
132+ ** 設定 state 只會為* 下一次* render 改變 state。** 在第一次 render 中,` number ` 為 ` 0 ` 。這是為什麼在* 該次 render 的* onClick handler 中,即便在呼叫了 ` setnumber(number + 1) ` 後, ` number ` 的值仍然為 ` 0 ` 的原因:
130133
131134``` js
132135< button onClick= {() => {
@@ -145,11 +148,9 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
1451483 . ` setNumber(number + 1) ` : ` number ` 為 ` 0 ` ,因此 ` setNumber(0 + 1) ` 。
146149 - React 準備在下一次 render 將 ` number ` 更改為 ` 1 ` 。
147150
148-
149151雖然呼叫了 ` setNumber(number + 1) ` 三次,在* 這一次 render 的* event handler 內的 ` number ` 一直都是 ` 0 ` ,所以等同於你把 state 設定為 ` 1 ` 三次。這就是為什麼在 event handler 執行結束後,React 用等於 ` 1 ` 而非 ` 3 ` 的 ` number ` 來重新 render component。
150152
151- 你也可以透過在心裡將程式碼中的 state 變數替換為它們的值來視覺化這一切。
152- 由於在* 這一次 render* 中,state 變數 ` number ` 的值為 ` 0 ` ,它的 event handler 看起來就像是這樣:
153+ 你也可以透過在心裡將程式碼中的 state 變數替換為它們的值來視覺化這一切。由於在* 這一次 render* 中,state 變數 ` number ` 的值為 ` 0 ` ,它的 event handler 看起來就像是這樣:
153154
154155``` js
155156< button onClick= {() => {
@@ -169,9 +170,10 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
169170}}> + 3 < / button>
170171```
171172
172- 這就是為什麼再次點擊按鈕會將計數器設置為 ` 2 ` ,然後在下一次點擊時會設置為 ` 3 ` ,依此類推。
173+ 這就是為什麼再次點擊按鈕會將計數器設定為 ` 2 ` ,然後在下一次點擊時會設定為 ` 3 ` ,依此類推。
173174
174175## 隨著時間改變的 state {/* state-over-time* /}
176+
175177嗯,那真是有趣。試著猜猜看點擊這個按鈕會彈出什麼提示框:
176178
177179<Sandpack >
@@ -203,13 +205,12 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
203205
204206如果你使用之前提到的替換法,你可以猜到提示框會顯示「0」:
205207
206-
207208``` js
208209setNumber (0 + 5 );
209210alert (0 );
210211```
211212
212- 但要是你在提示框上設置計時器 ,使其在 component 重新 render _ 之後_ 才觸發呢?那麼它會顯示「5」還是「0」?猜猜看!
213+ 但要是你在提示框上設定計時器 ,使其在 component 重新 render _ 之後_ 才觸發呢?那麼它會顯示「5」還是「0」?猜猜看!
213214
214215<Sandpack >
215216
@@ -248,6 +249,7 @@ setTimeout(() => {
248249 alert (0 );
249250}, 3000 );
250251```
252+
251253儲存在 React 裡的 state 在提示框執行時可能已改變,但它是用使用者與其互動當下的 state 快照來安排的!
252254
253255** 在同一次 render 裡,state 變數的值永遠不會改變** ,就算它的 event handler 的程式碼是非同步的。在* 該次 render 的* ` onClick ` 內,即使在呼叫 ` setNumber(number + 5) ` 之後,` number ` 的值仍然為 ` 0 ` 。當 React 透過呼叫 component 來替 UI「拍攝快照」時,state 的值「固定不變」。
@@ -291,7 +293,7 @@ export default function Form() {
291293 value= {message}
292294 onChange= {e => setMessage (e .target .value )}
293295 / >
294- < button type= " submit" > 傳送 < / button>
296+ < button type= " submit" > Send < / button>
295297 < / form>
296298 );
297299}
@@ -304,15 +306,18 @@ label, textarea { margin-bottom: 10px; display: block; }
304306</Sandpack >
305307
306308** React 會使 state 值在同一次 render 內的 event handler 保持「固定不變」。** 你不需要擔心 state 在程式碼執行時有所異動。
307- 但要是你希望在重新 render 之前讀取最新的 state 呢?你將會需要使用 [ state 的更新函數] ( /learn/queueing-a-series-of-state-updates ) ,這會下一章節中介紹!
309+
310+ 但要是你希望在重新 render 之前讀取最新的 state 呢?你將會需要使用 [ state 的更新函式] ( /learn/queueing-a-series-of-state-updates ) ,這會下一章節中介紹!
311+
308312<Recap >
313+
309314* 設定 state 會請求一次新的 render。
310315* React 將 state 儲存在 component 外,好比在架子上一樣。
311316* 當你呼叫 ` useState ` ,React 會* 為該次 render* 拍一張 state 的快照。
312317* 變數和 event handler 不會在重新 render 時「存活」。每次 render 都有自己的 event handler。
313318* 每次 render(和其內部的函式)始終會「看到」React 為* 該次* render 所提供的 state 快照。
314319* 你可以在內心替换 event handler 中的 state,類似於替換被 render 的 JSX。
315- * 過去創建的 event handler 保有它們被創建的那一次 render 中的 state 值。
320+ * 過去建立的 event handler 保有它們被建立的那一次 render 中的 state 值。
316321
317322</Recap >
318323
@@ -321,6 +326,7 @@ label, textarea { margin-bottom: 10px; display: block; }
321326<Challenges >
322327
323328#### 實作紅綠燈 {/* implement-a-traffic-light* /}
329+
324330以下是一個紅綠燈 component,按按鈕可以切換它的狀態:
325331
326332<Sandpack >
@@ -356,13 +362,14 @@ h1 { margin-top: 20px; }
356362
357363</Sandpack >
358364
359- 請在 click handler 裡添加一個 ` alert ` 。當燈是綠色的並顯示「Walk」時,點擊按鈕應顯示「Stop is next」。當燈是紅色的並顯示「Stop」時,點擊按鈕應顯示「Walk is next」。
365+ 請在 click handler 裡加入一個 ` alert ` 。當燈是綠色的並顯示「Walk」時,點擊按鈕應顯示「Stop is next」。當燈是紅色的並顯示「Stop」時,點擊按鈕應顯示「Walk is next」。
360366
361367無論你將 ` alert ` 放在呼叫 ` setWalk ` 之前還是之後,是否會有不同呢?
362368
363369<Solution >
364370
365371` alert ` 看起來應該像這樣:
372+
366373<Sandpack >
367374
368375``` js
@@ -422,6 +429,7 @@ alert(walk ? 'Stop is next' : 'Walk is next');
422429```
423430
424431因此,點擊「Change to Stop」時,會安排一次把 ` walk ` 設定為 ` false ` 的 render,並跳出「Stop is next」的提示框。
432+
425433</Solution >
426434
427- </Challenges >
435+ </Challenges >
0 commit comments