Skip to content

Commit ac4aa65

Browse files
authored
Add more explanations to Hooks API page (#1845)
* Add more explanations to API page * static * add info about useLayoutEffect * Update content/docs/hooks-reference.md Co-Authored-By: gaearon <[email protected]> * nits * nit
1 parent 806da34 commit ac4aa65

File tree

2 files changed

+36
-7
lines changed

2 files changed

+36
-7
lines changed

content/docs/hooks-faq.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ function Form() {
908908
const [text, updateText] = useState('');
909909
const textRef = useRef();
910910
911-
useLayoutEffect(() => {
911+
useEffect(() => {
912912
textRef.current = text; // Write it to the ref
913913
});
914914
@@ -949,7 +949,7 @@ function useEventCallback(fn, dependencies) {
949949
throw new Error('Cannot call an event handler while rendering.');
950950
});
951951
952-
useLayoutEffect(() => {
952+
useEffect(() => {
953953
ref.current = fn;
954954
}, [fn, ...dependencies]);
955955

content/docs/hooks-reference.md

+34-5
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ const [state, setState] = useState(() => {
9797

9898
If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the [`Object.is` comparison algorithm](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description).)
9999

100+
Note that React may still need to render that specific component again before bailing out. That shouldn't be a concern because React won't unnecessarily go "deeper" into the tree. If you're doing expensive calculations while rendering, you can optimize them with `useMemo`.
101+
100102
### `useEffect` {#useeffect}
101103

102104
```js
@@ -173,12 +175,24 @@ The array of dependencies is not passed as arguments to the effect function. Con
173175
### `useContext` {#usecontext}
174176

175177
```js
176-
const context = useContext(Context);
178+
const value = useContext(MyContext);
177179
```
178180

179-
Accepts a context object (the value returned from `React.createContext`) and returns the current context value, as given by the nearest context provider for the given context.
181+
Accepts a context object (the value returned from `React.createContext`) and returns the current context value for that context. The current context value is determined by the `value` prop of the nearest `<MyContext.Provider>` above the calling component in the tree.
182+
183+
When the nearest `<MyContext.Provider>` above the component updates, this Hook will trigger a rerender with the latest context `value` passed to that `MyContext` provider.
180184

181-
When the provider updates, this Hook will trigger a rerender with the latest context value.
185+
Don't forget that the argument to `useContext` must be the *context object itself*:
186+
187+
* **Correct:** `useContext(MyContext)`
188+
* **Incorrect:** `useContext(MyContext.Consumer)`
189+
* **Incorrect:** `useContext(MyContext.Provider)`
190+
191+
>Tip
192+
>
193+
>If you're familiar with the context API before Hooks, `useContext(MyContext)` is equivalent to `static contextType = MyContext` in a class, or to `<MyContext.Consumer>`.
194+
>
195+
>`useContext(MyContext)` only lets you *read* the context and subscribe to its changes. You still need a `<MyContext.Provider>` above in the tree to *provide* the value for this context.
182196
183197
## Additional Hooks {#additional-hooks}
184198

@@ -285,6 +299,8 @@ function Counter({initialCount}) {
285299

286300
If you return the same value from a Reducer Hook as the current state, React will bail out without rendering the children or firing effects. (React uses the [`Object.is` comparison algorithm](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description).)
287301

302+
Note that React may still need to render that specific component again before bailing out. That shouldn't be a concern because React won't unnecessarily go "deeper" into the tree. If you're doing expensive calculations while rendering, you can optimize them with `useMemo`.
303+
288304
### `useCallback` {#usecallback}
289305

290306
```js
@@ -356,7 +372,16 @@ function TextInputWithFocusButton() {
356372
}
357373
```
358374

359-
Note that `useRef()` is useful for more than the `ref` attribute. It's [handy for keeping any mutable value around](/docs/hooks-faq.html#is-there-something-like-instance-variables) similar to how you'd use instance fields in classes.
375+
Essentially, `useRef` is like a "box" that can hold a mutable value in its `.current` property.
376+
377+
You might be familiar with refs primarily as a way to [access the DOM](/docs/refs-and-the-dom.html). If you pass a ref object to React with `<div ref={myRef} />`, React will set its `.current` property to the corresponding DOM node whenever that node changes.
378+
379+
However, `useRef()` is useful for more than the `ref` attribute. It's [handy for keeping any mutable value around](/docs/hooks-faq.html#is-there-something-like-instance-variables) similar to how you'd use instance fields in classes.
380+
381+
This works because `useRef()` creates a plain JavaScript object. The only difference between `useRef()` and creating a `{current: ...}` object yourself is that `useRef` will give you the same ref object on every render.
382+
383+
Keep in mind that `useRef` *doesn't* notify you when its content changes. Mutating the `.current` property doesn't cause a re-render. If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use a [callback ref](/docs/hooks-faq.html#how-can-i-measure-a-dom-node) instead.
384+
360385

361386
### `useImperativeHandle` {#useimperativehandle}
362387

@@ -389,7 +414,11 @@ Prefer the standard `useEffect` when possible to avoid blocking visual updates.
389414

390415
> Tip
391416
>
392-
> If you're migrating code from a class component, `useLayoutEffect` fires in the same phase as `componentDidMount` and `componentDidUpdate`, so if you're unsure of which effect Hook to use, it's probably the least risky.
417+
> If you're migrating code from a class component, note `useLayoutEffect` fires in the same phase as `componentDidMount` and `componentDidUpdate`. However, **we recommend starting with `useEffect` first** and only trying `useLayoutEffect` if that causes a problem.
418+
>
419+
>If you use server rendering, keep in mind that *neither* `useLayoutEffect` nor `useEffect` can run until the JavaScript is downloaded. This is why React warns when a server-rendered component contains `useLayoutEffect`. To fix this, either move that logic to `useEffect` (if it isn't necessary for the first render), or delay showing that component until after the client renders (if the HTML looks broken until `useLayoutEffect` runs).
420+
>
421+
>To exclude a component that needs layout effects from the server-rendered HTML, render it conditionally with `showChild && <Child />` and defer showing it with `useEffect(() => { setShowChild(true); }, [])`. This way, the UI doesn't appear broken before hydration.
393422
394423
### `useDebugValue` {#usedebugvalue}
395424

0 commit comments

Comments
 (0)