diff --git a/src/content/reference/react/useContext.md b/src/content/reference/react/useContext.md index f69c49af9..f0c54b333 100644 --- a/src/content/reference/react/useContext.md +++ b/src/content/reference/react/useContext.md @@ -4,7 +4,7 @@ title: useContext -`useContext` is a React Hook that lets you read and subscribe to [context](/learn/passing-data-deeply-with-context) from your component. +`useContext` 是一個 React Hook,讓你從元件中讀取和訂閱(subscribe) [context](/learn/passing-data-deeply-with-context)。 ```js const value = useContext(SomeContext) @@ -16,11 +16,11 @@ const value = useContext(SomeContext) --- -## Reference {/*reference*/} +## 參考 {/*reference*/} ### `useContext(SomeContext)` {/*usecontext*/} -Call `useContext` at the top level of your component to read and subscribe to [context.](/learn/passing-data-deeply-with-context) +在元件的頂層呼叫 `useContext` 以讀取和訂閱 [context](/learn/passing-data-deeply-with-context)。 ```js import { useContext } from 'react'; @@ -30,30 +30,29 @@ function MyComponent() { // ... ``` -[See more examples below.](#usage) +[往下查看更多範例。](#usage) -#### Parameters {/*parameters*/} +#### 參數 {/*parameters*/} -* `SomeContext`: The context that you've previously created with [`createContext`](/reference/react/createContext). The context itself does not hold the information, it only represents the kind of information you can provide or read from components. +* `SomeContext`: 你已經預先用 [`createContext`](/reference/react/createContext) 創建的 context。這個 context 本身不儲存資訊,只代表元件可以提供或讀取的資訊種類。 -#### Returns {/*returns*/} +#### 回傳值 {/*returns*/} -`useContext` returns the context value for the calling component. It is determined as the `value` passed to the closest `SomeContext` above the calling component in the tree. If there is no such provider, then the returned value will be the `defaultValue` you have passed to [`createContext`](/reference/react/createContext) for that context. The returned value is always up-to-date. React automatically re-renders components that read some context if it changes. +`useContext` 會回傳呼叫元件的 context 值。這個值是由元件樹中距離呼叫元件上方最近的 `SomeContext`,所傳入的 `value` 來決定。如果沒有像這樣的 provider,回傳值就會是你在建立這個 context 時,傳入 [`createContext`](/reference/react/createContext) 的 `defaultValue`。回傳值總是最新的。如果 context 發生變化,React 會自動重新渲染(re-render)讀取這些 context 的元件。 -#### Caveats {/*caveats*/} +#### 注意事項 {/*caveats*/} -* `useContext()` call in a component is not affected by providers returned from the *same* component. The corresponding `` **needs to be *above*** the component doing the `useContext()` call. -* React **automatically re-renders** all the children that use a particular context starting from the provider that receives a different `value`. The previous and the next values are compared with the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison. Skipping re-renders with [`memo`](/reference/react/memo) does not prevent the children receiving fresh context values. -* If your build system produces duplicates modules in the output (which can happen with symlinks), this can break context. Passing something via context only works if `SomeContext` that you use to provide context and `SomeContext` that you use to read it are ***exactly* the same object**, as determined by a `===` comparison. +* 元件中所呼叫的 `useContext()` 並不會被 *同一個* 元件所回傳的 provider 影響。對應的 `` **必須位於呼叫 `useContext()` 的元件 *上方***。 +* React 會 **自動重新渲染** 所有使用特定 context 並從 provider 接收不同 `value` 的子元件。渲染之前和之後的值會用 [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) 來作比較。用 [`memo`](/reference/react/memo) 跳過重新渲染,並不能阻止子元件接收 context 的新值。 +* 如果你建置(build)的系統在輸出過程中產生重複的模組(可能會發生在符號連結(symlink)),會破壞 context。只在當用來提供 context 的 `SomeContext` 與用來讀取它的 `SomeContext` 是 ***完全* 相同的物件** 時,透過 context 傳遞資料才會正常運作,這是由 `===` 的比較所決定。 --- -## Usage {/*usage*/} +## 使用 {/*usage*/} +### 將資料傳入元件樹的深處 {/*passing-data-deeply-into-the-tree*/} -### Passing data deeply into the tree {/*passing-data-deeply-into-the-tree*/} - -Call `useContext` at the top level of your component to read and subscribe to [context.](/learn/passing-data-deeply-with-context) +在元件的頂層呼叫 `useContext` 以讀取和訂閱 [context](/learn/passing-data-deeply-with-context)。 ```js [[2, 4, "theme"], [1, 4, "ThemeContext"]] import { useContext } from 'react'; @@ -63,9 +62,9 @@ function Button() { // ... ``` -`useContext` returns the context value for the context you passed. To determine the context value, React searches the component tree and finds **the closest context provider above** for that particular context. +`useContext` 針對你傳入的 context 回傳 context 值。為了決定 context 值,React 搜尋元件樹,並尋找針對這個 context,**上方距離最近的 context provider**。 -To pass context to a `Button`, wrap it or one of its parent components into the corresponding context provider: +要傳入 context 給 `Button` 的話,在它或其中一個父元件外,包上一層對應的 context provider: ```js [[1, 3, "ThemeContext"], [2, 3, "\\"dark\\""], [1, 5, "ThemeContext"]] function MyPage() { @@ -77,15 +76,15 @@ function MyPage() { } function Form() { - // ... renders buttons inside ... + // ⋯⋯在這之中渲染按鈕⋯⋯ } ``` -It doesn't matter how many layers of components there are between the provider and the `Button`. When a `Button` *anywhere* inside of `Form` calls `useContext(ThemeContext)`, it will receive `"dark"` as the value. +Provider 和 `Button` 之間有幾層元件並不重要。當在 `Form` 以內不管在哪裡的 `Button` 呼叫 `useContext(ThemeContext)`,就會收到 `"dark"` 作為 context 的值。 -`useContext()` always looks for the closest provider *above* the component that calls it. It searches upwards and **does not** consider providers in the component from which you're calling `useContext()`. +`useContext()` 必定尋找呼叫元件 *上方* 最近的 provider。它只會往上搜尋,**不會考慮** 你從 provider 下的哪一個元件呼叫 `useContext()`。 @@ -106,9 +105,9 @@ export default function MyApp() { function Form() { return ( - - - + + + ); } @@ -175,9 +174,9 @@ function Button({ children }) { --- -### Updating data passed via context {/*updating-data-passed-via-context*/} +### 以 context 更新傳遞的資料 {/*updating-data-passed-via-context*/} -Often, you'll want the context to change over time. To update context, combine it with [state.](/reference/react/useState) Declare a state variable in the parent component, and pass the current state down as the context value to the provider. +通常,你會希望 context 隨著時間變化。要更新 context 的話,搭配使用 context 和 [state](/reference/react/useState)。在父元件宣告一個狀態變數,並將當前狀態作為 context 的值 向下傳遞給 provider。 ```js {2} [[1, 4, "ThemeContext"], [2, 4, "theme"], [1, 11, "ThemeContext"]] function MyPage() { @@ -188,20 +187,20 @@ function MyPage() { ); } ``` -Now any `Button` inside of the provider will receive the current `theme` value. If you call `setTheme` to update the `theme` value that you pass to the provider, all `Button` components will re-render with the new `'light'` value. +現在 provider 中的任何 `Button` 都會收到當前的 `theme` 的值。如果呼叫 `setTheme` 來更新你傳給 provider 的 `theme` 值,所有的 `Button` 元件都會以新的 `'light'` 值,重新渲染。 - + -#### Updating a value via context {/*updating-a-value-via-context*/} +#### 以 context 更新數值 {/*updating-a-value-via-context*/} -In this example, the `MyApp` component holds a state variable which is then passed to the `ThemeContext` provider. Checking the "Dark mode" checkbox updates the state. Changing the provided value re-renders all the components using that context. +在這個範例中,`MyApp` 元件有一個在稍候會傳給 `ThemeContext` provider 的狀態變數。試著改變「Dark 模式」核取方塊來更新狀態。改變提供的值,會讓所有使用這個 context 的元件重新渲染。 @@ -223,7 +222,7 @@ export default function MyApp() { setTheme(e.target.checked ? 'dark' : 'light') }} /> - Use dark mode + 使用 dark 模式 ) @@ -231,9 +230,9 @@ export default function MyApp() { function Form({ children }) { return ( - - - + + + ); } @@ -299,13 +298,13 @@ function Button({ children }) { -Note that `value="dark"` passes the `"dark"` string, but `value={theme}` passes the value of the JavaScript `theme` variable with [JSX curly braces.](/learn/javascript-in-jsx-with-curly-braces) Curly braces also let you pass context values that aren't strings. +現在 `value="dark"` 傳入 `"dark"` 字串,但 `value={theme}` 是以 [JSX 花括號(curly brace)](/learn/javascript-in-jsx-with-curly-braces) 傳入 JavaScript 的 `theme` 變數。花括號可以讓你傳入非字串的 context 值。 -#### Updating an object via context {/*updating-an-object-via-context*/} +#### 以 context 更新物件 {/*updating-an-object-via-context*/} -In this example, there is a `currentUser` state variable which holds an object. You combine `{ currentUser, setCurrentUser }` into a single object and pass it down through the context inside the `value={}`. This lets any component below, such as `LoginButton`, read both `currentUser` and `setCurrentUser`, and then call `setCurrentUser` when needed. +在這個範例中,`currentUser` 狀態變數中有一個物件。你把 `{ currentUser, setCurrentUser }` 組合成單一個物件,並在 `value={}` 中向下傳遞。這會讓下方像是 `LoginButton` 這樣的任何一個元件,同時讀取 `currentUser` 和 `setCurrentUser`,並在需要的時候呼叫 `setCurrentUser`。 @@ -330,7 +329,7 @@ export default function MyApp() { function Form({ children }) { return ( - + ); @@ -343,13 +342,13 @@ function LoginButton() { } = useContext(CurrentUserContext); if (currentUser !== null) { - return

You logged in as {currentUser.name}.

; + return

你已登入為 {currentUser.name} 。

; } return ( + }}>以 Advika 登入 ); } @@ -395,9 +394,9 @@ label { -#### Multiple contexts {/*multiple-contexts*/} +#### 多個 contexts {/*multiple-contexts*/} -In this example, there are two independent contexts. `ThemeContext` provides the current theme, which is a string, while `CurrentUserContext` holds the object representing the current user. +在這個範例中,有兩個相互獨立的 context。`ThemeContext` 提供當前的主題,為字串;而 `CurrentUserContext` 中是一個代表目前使用者的物件。 @@ -427,7 +426,7 @@ export default function MyApp() { setTheme(e.target.checked ? 'dark' : 'light') }} /> - Use dark mode + 使用 dark 模式 @@ -437,7 +436,7 @@ export default function MyApp() { function WelcomePanel({ children }) { const {currentUser} = useContext(CurrentUserContext); return ( - + {currentUser !== null ? : @@ -449,7 +448,7 @@ function WelcomePanel({ children }) { function Greeting() { const {currentUser} = useContext(CurrentUserContext); return ( -

You logged in as {currentUser.name}.

+

你已登入為 {currentUser.name} 。

) } @@ -461,7 +460,7 @@ function LoginForm() { return ( <> ); @@ -612,7 +611,7 @@ function MyProviders({ children, theme, setTheme }) { function WelcomePanel({ children }) { const {currentUser} = useContext(CurrentUserContext); return ( - + {currentUser !== null ? : @@ -624,7 +623,7 @@ function WelcomePanel({ children }) { function Greeting() { const {currentUser} = useContext(CurrentUserContext); return ( -

You logged in as {currentUser.name}.

+

你已登入為 {currentUser.name} 。

) } @@ -636,7 +635,7 @@ function LoginForm() { return ( <> ); @@ -947,25 +946,25 @@ ul, li { margin: 0; padding: 0; } --- -### Specifying a fallback default value {/*specifying-a-fallback-default-value*/} +### 指定備用預設值 {/*specifying-a-fallback-default-value*/} -If React can't find any providers of that particular context in the parent tree, the context value returned by `useContext()` will be equal to the default value that you specified when you [created that context](/reference/react/createContext): +如果 React 在父元件樹中,找不到任何特定 context 的 provider,`useContext()` 所回傳的 context 值就會和你[創建 context](/reference/react/createContext) 時指定的預設值相同: ```js [[1, 1, "ThemeContext"], [3, 1, "null"]] const ThemeContext = createContext(null); ``` -The default value **never changes**. If you want to update context, use it with state as [described above.](#updating-data-passed-via-context) +這個預設值 **不會改變**。如果想更新 context,像[本文上面所說的](#updating-data-passed-via-context)搭配狀態來使用。 -Often, instead of `null`, there is some more meaningful value you can use as a default, for example: +通常,除了 `null`,有更多可以作為預設,且更有意義的值,例如: ```js [[1, 1, "ThemeContext"], [3, 1, "light"]] const ThemeContext = createContext('light'); ``` -This way, if you accidentally render some component without a corresponding provider, it won't break. This also helps your components work well in a test environment without setting up a lot of providers in the tests. +用這個方式,如果不小心在沒有對應 provider 的情況下渲染元件,也不會壞掉。這也能幫助元件在測試環境順利運作,而不用在測試中設定很多 providers。 -In the example below, the "Toggle theme" button is always light because it's **outside any theme context provider** and the default context theme value is `'light'`. Try editing the default theme to be `'dark'`. +下面的範例中,「切換主題」按鈕總是 light,因為它在 **任何 theme context provider 之外**,而且主題的預設值是 `'light'`。試著把預設主題更改為 `'dark'`。 @@ -984,7 +983,7 @@ export default function MyApp() { ) @@ -992,9 +991,9 @@ export default function MyApp() { function Form({ children }) { return ( - - - + + + ); } @@ -1062,9 +1061,9 @@ function Button({ children, onClick }) { --- -### Overriding context for a part of the tree {/*overriding-context-for-a-part-of-the-tree*/} +### 在元件樹的某些部分覆寫 context {/*overriding-context-for-a-part-of-the-tree*/} -You can override the context for a part of the tree by wrapping that part in a provider with a different value. +你可以在元件樹的某些部分覆寫(override) context,以不同的值包裹 provider 中的某些部分。 ```js {3,5} @@ -1076,13 +1075,13 @@ You can override the context for a part of the tree by wrapping that part in a p ``` -You can nest and override providers as many times as you need. +你可以依照需求多次嵌套(nest)並覆寫 provider。 - + -#### Overriding a theme {/*overriding-a-theme*/} +#### 覆寫主題 {/*overriding-a-theme*/} -Here, the button *inside* the `Footer` receives a different context value (`"light"`) than the buttons outside (`"dark"`). +`Footer` *中* 的按鈕接收的 context 值(`"light"`),不同於 `Footer` 外的按鈕(`"dark"`)。 @@ -1101,9 +1100,9 @@ export default function MyApp() { function Form() { return ( - - - + + +