Skip to content

Commit

Permalink
docs(advanced-recipes): initialize atom on render (pmndrs#1293)
Browse files Browse the repository at this point in the history
* docs: initialize atom on demand

* chore: include example

* docs: rename on-demand to on-render

* docs: typos

* docs: grammar

* docs: move to guides

* chore: remove advanced-guides
  • Loading branch information
austinwoon authored Jul 21, 2022
1 parent 09fad0a commit 466499d
Showing 1 changed file with 87 additions and 0 deletions.
87 changes: 87 additions & 0 deletions docs/guides/initialize-atom-on-render.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
title: Initializing Atom State on Render
description: How to initialize atom state on initial render
nav: 3.12
---

There are times when you need to create an reusable component which uses atoms.

These atoms' initial state are determined by the props passed to the component.

Below is a basic example of illustrating how you can use `Provider` and its prop, `initialValues`, to initialize state.

### Basic Example

> CodeSandbox link: [codesandbox](https://codesandbox.io/s/strange-tdd-gb1eo0?file=/src/App.js).
Consider a basic example where you have a reusable `TextDisplay` component that allows you to display and update plain text.

This component has two child components, `PrettyText` and `UpdateTextInput`.

- `PrettyText` displays the text in blue.
- `UpdateTextInput` is an input field which updates the text value.

As opposed to passing `text` as a prop in the two child components, you decided that the `text` state should be shared between components as an atom.

To make `TextDisplay` component reusable, we take in a prop `initialTextValue`, which determines the initial state of the `text` atom.

To tie `initialTextValue` to `textAtom`, we wrap the child components in a `Provider`. Then, we populate the `initialValues` array of atom tuples with the initial values.

```jsx
const textAtom = atom('')

const PrettyText = () => {
const [text] = useAtom(textAtom)
return (
<>
<text
style={{
color: 'blue',
}}>
{text}
</text>
</>
)
}

const UpdateTextInput = () => {
const [text, setText] = useAtom(textAtom)
const handleInputChange = (e) => {
setText(e.target.value)
}
return (
<>
<input onChange={handleInputChange} value={text} />
</>
)
}

export const TextDisplay = ({ initialTextValue }) => {
return (
// initialising on state with prop on render here
<Provider initialValues={[[textAtom, initialTextValue]]}>
<PrettyText />
<br />
<UpdateTextInput />
</Provider>
)
}
```

Now, we can easily resue `TextDisplay` component with different initial text values despite them referencing the "same" atom.

```jsx
export default function App() {
return (
<div className="App">
<TextDisplay initialTextValue="initial text value 1" />

<TextDisplay initialTextValue="initial text value 2" />
</div>
)
}
```

This behavior is due to our child components looking for the lowest commmon `Provider` ancestor to derive its value.

For more information on `Provider` behavior, please read the docs [here](https://jotai.org/docs/api/core#provider).

0 comments on commit 466499d

Please sign in to comment.