diff --git a/beta/src/components/Layout/Toc.tsx b/beta/src/components/Layout/Toc.tsx
index 2fe40c7d..ecaf6a20 100644
--- a/beta/src/components/Layout/Toc.tsx
+++ b/beta/src/components/Layout/Toc.tsx
@@ -41,7 +41,7 @@ export function Toc({
{h.text}
diff --git a/beta/src/pages/apis/usestate.md b/beta/src/pages/apis/usestate.md
index 5ef6f467..bc8b40e9 100644
--- a/beta/src/pages/apis/usestate.md
+++ b/beta/src/pages/apis/usestate.md
@@ -20,6 +20,11 @@ title: useState
- [Avoiding recreating the initial state](#avoiding-recreating-the-initial-state)
- [Resetting state with a key](#resetting-state-with-a-key)
- [Storing information from previous renders](#storing-information-from-previous-renders)
+- [Troubleshooting](#troubleshooting)
+ - [I’ve updated the state, but logging gives me the old value](#ive-updated-the-state-but-logging-gives-me-the-old-value)
+ - [I've updated the state, but the screen doesn't update](#ive-updated-the-state-but-the-screen-doesnt-update)
+ - [I'm getting an error: "Too many re-renders"](#im-getting-an-error-too-many-re-renders)
+
## Reference {/*reference*/}
@@ -278,22 +283,6 @@ button { display: block; margin-top: 10px; }
Read [state as a component's memory](/learn/state-a-components-memory) to learn more.
-
-
-Calling the `set` function only [affects the next render](/learn/state-as-a-snapshot) and **does not change state in the running code**:
-
-```js {3,4}
-function handleClick() {
- console.log(count); // 0
- setCount(count + 1); // Request a re-render with 1
- console.log(count); // Still 0!
-}
-```
-
-If you need the next state, you can save it in a variable before passing it to the `set` function.
-
-
-
---
### Updating state based on the previous state {/*updating-state-based-on-the-previous-state*/}
@@ -488,6 +477,118 @@ input { margin-left: 5px; }
+### Form (nested object) {/*form-nested-object*/}
+
+In this example, the state is more nested. When you update nested state, you need to create a copy of the object you're updating, as well as any objects "containing" it on the way upwards. Read [updating a nested object](/learn/updating-objects-in-state#updating-a-nested-object) to learn more.
+
+
+
+```js
+import { useState } from 'react';
+
+export default function Form() {
+ const [person, setPerson] = useState({
+ name: 'Niki de Saint Phalle',
+ artwork: {
+ title: 'Blue Nana',
+ city: 'Hamburg',
+ image: 'https://i.imgur.com/Sd1AgUOm.jpg',
+ }
+ });
+
+ function handleNameChange(e) {
+ setPerson({
+ ...person,
+ name: e.target.value
+ });
+ }
+
+ function handleTitleChange(e) {
+ setPerson({
+ ...person,
+ artwork: {
+ ...person.artwork,
+ title: e.target.value
+ }
+ });
+ }
+
+ function handleCityChange(e) {
+ setPerson({
+ ...person,
+ artwork: {
+ ...person.artwork,
+ city: e.target.value
+ }
+ });
+ }
+
+ function handleImageChange(e) {
+ setPerson({
+ ...person,
+ artwork: {
+ ...person.artwork,
+ image: e.target.value
+ }
+ });
+ }
+
+ return (
+ <>
+
+
+
+
+
+ {person.artwork.title}
+ {' by '}
+ {person.name}
+
+ (located in {person.artwork.city})
+
+
+ >
+ );
+}
+```
+
+```css
+label { display: block; }
+input { margin-left: 5px; margin-bottom: 5px; }
+img { width: 200px; height: 200px; }
+```
+
+
+
+
+
### List (array) {/*list-array*/}
In this example, the `todos` state variable holds an array. Each button handler calls `setTodos` with the next version of that array. The `[...todos]` spread syntax, `todos.map()` and `todos.filter()` ensure the state array is replaced rather than mutated.
@@ -655,6 +756,93 @@ ul, li { margin: 0; padding: 0; }
+### Writing concise update logic with Immer {/*writing-concise-update-logic-with-immer*/}
+
+If updating arrays and objects without mutation feels tedious, you can use a library like [Immer](https://github.com/immerjs/use-immer) to reduce repetitive code. Immer lets you write concise code as if you were mutating objects, but under the hood it performs immutable updates:
+
+
+
+```js
+import { useState } from 'react';
+import { useImmer } from 'use-immer';
+
+let nextId = 3;
+const initialList = [
+ { id: 0, title: 'Big Bellies', seen: false },
+ { id: 1, title: 'Lunar Landscape', seen: false },
+ { id: 2, title: 'Terracotta Army', seen: true },
+];
+
+export default function BucketList() {
+ const [list, updateList] = useImmer(initialList);
+
+ function handleToggle(artworkId, nextSeen) {
+ updateList(draft => {
+ const artwork = draft.find(a =>
+ a.id === artworkId
+ );
+ artwork.seen = nextSeen;
+ });
+ }
+
+ return (
+ <>
+