Skip to content

Commit 28220b7

Browse files
author
Jack Pope
committed
Contain changes within canary block
1 parent f687157 commit 28220b7

File tree

2 files changed

+52
-27
lines changed

2 files changed

+52
-27
lines changed

src/content/learn/manipulating-the-dom-with-refs.md

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ This is because **Hooks must only be called at the top-level of your component.*
211211

212212
One possible way around this is to get a single ref to their parent element, and then use DOM manipulation methods like [`querySelectorAll`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll) to "find" the individual child nodes from it. However, this is brittle and can break if your DOM structure changes.
213213

214-
Another solution is to **pass a function to the `ref` attribute.** This is called a [`ref` callback.](/reference/react-dom/components/common#ref-callback) React will call your ref callback with the DOM node when it's time to set the ref, and call your cleanup function when it's time to clear it. This lets you maintain your own array or a [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map), and access any ref by its index or some kind of ID.
214+
Another solution is to **pass a function to the `ref` attribute.** This is called a [`ref` callback.](/reference/react-dom/components/common#ref-callback) React will call your ref callback with the DOM node when it's time to set the ref, and with `null` when it's time to clear it. This lets you maintain your own array or a [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map), and access any ref by its index or some kind of ID.
215215

216216
This example shows how you can use this approach to scroll to an arbitrary node in a long list:
217217

@@ -242,19 +242,9 @@ export default function CatFriends() {
242242
return itemsRef.current;
243243
}
244244

245-
async function addCat() {
246-
setCatList((prev) => [createCatImg(prev.length + 100), ...prev]);
247-
}
248-
249-
async function removeCat() {
250-
setCatList((prev) => prev.slice(1));
251-
}
252-
253245
return (
254246
<>
255247
<nav>
256-
<button onClick={addCat}>Add Cat</button>
257-
<button onClick={removeCat}>Remove Cat</button>
258248
<button onClick={() => scrollToCat(catList[0])}>Tom</button>
259249
<button onClick={() => scrollToCat(catList[5])}>Maru</button>
260250
<button onClick={() => scrollToCat(catList[9])}>Jellylorum</button>
@@ -266,11 +256,11 @@ export default function CatFriends() {
266256
key={cat}
267257
ref={(node) => {
268258
const map = getMap();
259+
if (node) {
269260
map.set(cat, node);
270-
271-
return () => {
261+
} else {
272262
map.delete(cat);
273-
};
263+
}
274264
}}
275265
>
276266
<img src={cat} />
@@ -285,16 +275,12 @@ export default function CatFriends() {
285275
function setupCatList() {
286276
const catList = [];
287277
for (let i = 0; i < 10; i++) {
288-
catList.push(createCatImg(i));
278+
catList.push("https://loremflickr.com/320/240/cat?lock=" + i);
289279
}
290280

291281
return catList;
292282
}
293283

294-
function createCatImg(i) {
295-
return "https://loremflickr.com/320/240/cat?lock=" + i;
296-
}
297-
298284
```
299285

300286
```css
@@ -342,18 +328,40 @@ In this example, `itemsRef` doesn't hold a single DOM node. Instead, it holds a
342328
key={cat.id}
343329
ref={node => {
344330
const map = getMap();
345-
// Add to the map
331+
if (node) {
332+
// Add to the Map
333+
map.set(cat, node);
334+
} else {
335+
// Remove from the Map
336+
map.delete(cat);
337+
}
338+
}}
339+
>
340+
```
341+
342+
This lets you read individual DOM nodes from the Map later.
343+
344+
<Canary>
345+
346+
This example shows another approach for managing the Map with a `ref` callback cleanup function.
347+
348+
```js
349+
<li
350+
key={cat.id}
351+
ref={node => {
352+
const map = getMap();
353+
// Add to the Map
346354
map.set(cat, node);
347355

348356
return () => {
349-
// Remove from the map
357+
// Remove from the Map
350358
map.delete(cat);
351359
};
352360
}}
353361
>
354362
```
355363

356-
This lets you read individual DOM nodes from the Map later.
364+
</Canary>
357365

358366
</DeepDive>
359367

src/content/reference/react-dom/components/common.md

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -251,21 +251,38 @@ Instead of a ref object (like the one returned by [`useRef`](/reference/react/us
251251

252252
[See an example of using the `ref` callback.](/learn/manipulating-the-dom-with-refs#how-to-manage-a-list-of-refs-using-a-ref-callback)
253253

254-
When the `<div>` DOM node is added to the screen, React will call your `ref` callback with the DOM `node` as the argument. If a cleanup function is returned, React will call it when that `<div>` DOM node is removed. Without a cleanup function, React will call your `ref` callback again with `null` when the node is removed.
254+
When the `<div>` DOM node is added to the screen, React will call your `ref` callback with the DOM `node` as the argument. When that `<div>` DOM node is removed, React will call your `ref` callback with `null`.
255255

256-
React will also call your `ref` callback whenever you pass a *different* `ref` callback. In the above example, `(node) => { ... }` is a different function on every render. When your component re-renders, React will call the *previous* callback's cleanup function if provided. If not cleanup function is defined, the `ref` callback will be called with `null` as the argument. The *next* function will be called with the DOM node.
256+
React will also call your `ref` callback whenever you pass a *different* `ref` callback. In the above example, `(node) => { ... }` is a different function on every render. When your component re-renders, the *previous* function will be called with `null` as the argument, and the *next* function will be called with the DOM node.
257257

258258
#### Parameters {/*ref-callback-parameters*/}
259259

260-
* `node`: A DOM node or `null`. React will pass you the DOM node when the ref gets attached, and `null` when the `ref` gets detached if no cleanup function is returned. Unless you pass the same function reference for the `ref` callback on every render, the callback will get temporarily detached and re-attached during every re-render of the component.
260+
* `node`: A DOM node or `null`. React will pass you the DOM node when the ref gets attached, and `null` when the `ref` gets detached. Unless you pass the same function reference for the `ref` callback on every render, the callback will get temporarily detached and re-attached during every re-render of the component.
261+
262+
<Canary>
261263

262264
#### Returns {/*returns*/}
263265

264-
* <CanaryBadge title="This feature is only available in the Canary channel" /> **optional** `cleanup function`: When the `ref` is detached, React will call the cleanup function. If a function is not returned by the `ref` callback, React will call the callback again with `null` as the argument when the `ref` gets detached.
266+
* **optional** `cleanup function`: When the `ref` is detached, React will call the cleanup function. If a function is not returned by the `ref` callback, React will call the callback again with `null` as the argument when the `ref` gets detached.
267+
268+
```js
269+
270+
<div ref={(node) => {
271+
console.log(node);
272+
273+
return () => {
274+
console.log('Clean up', node)
275+
}
276+
}}>
277+
278+
```
265279

266280
#### Caveats {/*caveats*/}
267281

268-
* <CanaryBadge title="This feature is only available in the Canary channel" /> When Strict Mode is on, React will **run one extra development-only setup+cleanup cycle** before the first real setup. This is a stress-test that ensures that your cleanup logic "mirrors" your setup logic and that it stops or undoes whatever the setup is doing. If this causes a problem, implement the cleanup function.
282+
* When Strict Mode is on, React will **run one extra development-only setup+cleanup cycle** before the first real setup. This is a stress-test that ensures that your cleanup logic "mirrors" your setup logic and that it stops or undoes whatever the setup is doing. If this causes a problem, implement the cleanup function.
283+
* When you pass a *different* `ref` callback, React will call the *previous* callback's cleanup function if provided. If not cleanup function is defined, the `ref` callback will be called with `null` as the argument. The *next* function will be called with the DOM node.
284+
285+
</Canary>
269286

270287
---
271288

0 commit comments

Comments
 (0)