[Beta] Diagrams for Sharing State (#4644)

This commit is contained in:
dan
2022-05-07 23:56:08 +01:00
committed by GitHub
parent d8f92c1bfc
commit fca358333d
33 changed files with 581 additions and 37 deletions

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 35 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 35 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 42 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 42 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 49 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 49 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 40 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 40 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 53 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 752 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 533 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 519 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 835 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 609 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 884 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 895 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 347 KiB

View File

@@ -16,9 +16,11 @@ interface DiagramProps {
function Caption({text}: {text: string}) {
return (
<figcaption className="p-1 sm:p-2 mt-0 sm:mt-0 text-gray-40 text-base lg:text-lg text-center leading-tight">
{text}
</figcaption>
<div className="w-full table">
<figcaption className="p-1 sm:p-2 mt-0 sm:mt-0 text-gray-40 text-base lg:text-lg text-center leading-tight table-caption">
{text}
</figcaption>
</div>
);
}

View File

@@ -75,6 +75,22 @@ h3, p { margin: 5px 0px; }
Notice how pressing one panel's button does not affect the other panel--they are independent.
<DiagramGroup>
<Diagram name="sharing_state_child" height={368} width={478} alt="Diagram showing a tree of three components, one parent labeled Accordion and two children labeled Panel. Both Panel components contain isActive with value false.">
Initially, each `Panel`'s `isActive` state is `false`, so they both appear collapsed
</Diagram>
<Diagram name="sharing_state_child_clicked" height={368} width={481} alt="The same diagram as the previous, with the isActive of the first child Panel component highlighted indicating a click with the isActive value set to true. The second Panel component still contains value false." >
Clicking either `Panel`'s button will only update that `Panel`'s `isActive` state alone, so each panel expands independently
</Diagram>
</DiagramGroup>
**But now let's say you want to change it so that only one panel is expanded at any given time.** With that design, expanding the second panel should collapse the first one. How would you do that?
To coordinate these two panels, you need to "lift their state up" to a parent component in three steps:
@@ -85,8 +101,6 @@ To coordinate these two panels, you need to "lift their state up" to a parent co
This will allow the `Accordion` component to coordinate both `Panel`s and only expand one at a time.
<img alt="On the left are two components each owning their own state values. On the right, they are the children of a parent component that owns both their state values." src="/images/docs/sketches/s_lifting-state-up.png" />
### Step 1: Remove state from the child components {/*step-1-remove-state-from-the-child-components*/}
You will give control of the `Panel`'s `isActive` to its parent component. This means that the parent component will pass `isActive` to `Panel` as a prop instead. Start by **removing this line** from the `Panel` component:
@@ -164,8 +178,6 @@ Try editing the hardcoded `isActive` values in the `Accordion` component and see
Lifting state up often changes the nature of what you're storing as state.
<img alt="The parent component passes the state setting function to both child components." src="/images/docs/sketches/s_passing-functions-down.png" />
In this case, only one panel should be active at a time. This means that the `Accordion` common parent component needs to keep track of *which* panel is the active one. Instead of a `boolean` value, it could use a number as the index of the active `Panel` for the state variable:
```js
@@ -256,6 +268,22 @@ h3, p { margin: 5px 0px; }
This completes lifting state up! Moving state into the common parent component allowed you to coordinate the two panels. Using the active index instead of two "is shown" flags ensured that only one panel is active at a given time. And passing down the event handler to the child allowed the child to change the parent's state.
<DiagramGroup>
<Diagram name="sharing_state_parent" height={385} width={521} alt="Diagram showing a tree of three components, one parent labeled Accordion and two children labeled Panel. Accordion contains an activeIndex value of zero which turns into isActive value of true passed to the first Panel, and isActive value of false passed to the second Panel." >
Initially, `Accordion`'s `activeIndex` is `0`, so the first `Panel` receives `isActive = true`
</Diagram>
<Diagram name="sharing_state_parent_clicked" height={385} width={521} alt="The same diagram as the previous, with the activeIndex value of the parent Accordion component highlighted indicating a click with the value changed to one. The flow to both of the children Panel components is also highlighted, and the isActive value passed to each child is set to the opposite: false for the first Panel and true for the second one." >
When `Accordion`'s `activeIndex` state changes to `1`, the second `Panel` receives `isActive = true` instead
</Diagram>
</DiagramGroup>
<DeepDive title="Controlled and Uncontrolled Components">
It is common to call a component with some local state "uncontrolled". For example, the original `Panel` component with an `isActive` state variable is uncontrolled because its parent cannot influence whether the panel is active or not.