JotaiJotai

状態
Primitive and flexible state management for React

Additional

Provider

const Provider: React.FC<{
initialValues?: Iterable<readonly [AnyAtom, unknown]>
scope?: Scope
}>

Atom configs don't hold values. Atom values reside in separate stores. A Provider is a component that contains a store and provides atom values under the component tree. A Provider works like React context provider. If you don't use a Provider, it works as provider-less mode with a default store. A Provider will be necessary if we need to hold different atom values for different component trees. Provider also has some capabilities described below, which doesn't exist in the provider-less mode.

const Root = () => (
<Provider>
<App />
</Provider>
)

initialValues prop

A Provider accepts an optional prop initialValues, with which you can specify some initial atom values. The use cases of this are testing and server side rendering.

Example

const TestRoot = () => (
<Provider
initialValues={[
[atom1, 1],
[atom2, 'b'],
]}>
<Component />
</Provider>
)

TypeScript

The initialValues prop is not type friendly. We can mitigate it by using a helper function.

const createInitialValues = () => {
const initialValues: (readonly [Atom<unknown>, unknown])[] = []
const get = () => initialValues
const set = <Value>(anAtom: Atom<Value>, value: Value) => {
initialValues.push([anAtom, value])
}
return { get, set }
}

scope prop

A Provider accepts an optional prop scope that you can use for a scoped Provider. When using atoms with a scope, the provider with the same scope is used. The recommendation for the scope value is a unique symbol. The primary use case of scope is for library usage.

Example

const myScope = Symbol()
const anAtom = atom('')
const LibraryComponent = () => {
const [value, setValue] = useAtom(anAtom, myScope)
// ...
}
const LibraryRoot = ({ children }) => (
<Provider scope={myScope}>{children}</Provider>
)

useSetAtom

const switchAtom = atom(false)
const SetTrueButton = () => {
const setCount = useSetAtom(switchAtom)
const setTrue = () => setCount(true)
return (
<div>
<button onClick={setTrue}>Set True</button>
</div>
)
}
const SetFalseButton = () => {
const setCount = useSetAtom(switchAtom)
const setFalse = () => setCount(false)
return (
<div>
<button onClick={setFalse}>Set False</button>
</div>
)
}
export default function App() {
const state = useAtomValue(switchAtom)
return (
<div>
State: <b>{state.toString()}</b>
<SetTrueButton />
<SetFalseButton />
</div>
)
}

In case you create a write only atom where the value never changes you can use the useSetAtom hook. useSetAtom is premature optimization in this scenario.

For primitive values if you use const [, setValue] = useAtom(valueAtom) it can cause unnecessary re-renders, so useSetAtom helps to avoid those extra re-renders.

useAtomValue

const countAtom = atom(0)
const Counter = () => {
const setCount = useSetAtom(countAtom)
const count = useAtomValue(countAtom)
return (
<>
<div>count: {count}</div>
<button onClick={() => setCount(count + 1)}>+1</button>
</>
)
}

Similar to the useSetAtom hook, useAtomValue allows you to access a read-only atom.