Hooks
useObservable
The useObservable
hook can be used to create an observable within a React component. This can be useful when state is specific to the lifetime of the component, or to hold multiple values in local state.
Its observables will be tracked for re-rendering the same as any other observable, so use get()
to track it.
import { useObservable } from "@legendapp/state/react"
function Component() {
const state = useObservable({
title: 'Title',
first: '',
last: '',
profile: {...}
})
return (
<div>
<div>{state.title.get()}</div>
<Input text={state.first} />
<Input text={state.last} />
<Profile profile={state.profile} />
</div>
)
// Tracking: [state.title]
}
Using with Context
You may prefer passing state through Context rather than (or in addition to) having a global state. To do that you can simply add the observable to your Context as usual, and consume the Context from child component. The observable itself is a stable object so changing the value of an observable will not cause a re-render.
import { createContext, useContext } from "react"
import { useObservable } from "@legendapp/state/react"
const StateContext = createContext()
function App() {
const state = useObservable({
profile: {
name: ''
}
})
return (
<StateContext.Provider value={state}>
<div>
<Sidebar />
<Main />
</div>
</StateContext.Provider>
)
}
function Sidebar() {
// StateContext will never change so this will never cause a render
const state = useContext(StateContext);
const { name } = state.profile;
// Tracking: [state.profile.name]
return (
<div>
Name: {name}
</div>
)
}
useComputed
useComputed
is like useObservable
and creates a computed observable.
import { useComputed } from "@legendapp/state/react"
const obs = observable({ test: 10, test2: 20 })
function Component() {
const sum = useComputed(() => obs.test.get() + obs.test2.get())
return (
<div>Sum: {sum}</div>
)
}
useObserve
useObserve
creates an observe which you can use to take actions when observables change. This is similar to useEffect
for observables which runs only when observables change and not because of rendering.
Like observe
, useObserve
has an optional second callback parameter which will run after the selector, and does not track changes. This can be useful for observing an event
or a single observable
.
Note that useObserve
runs during component render, not after render like useEffect
. If you want an observer that runs after render, see useObserveEffect.
import { useObserve, event } from "@legendapp/state"
import { useObserve } from "@legendapp/state/react"
import { Legend } from "@legendapp/state/react-components"
const eventUpdateTitle = event()
function ProfilePage() {
// This component never re-renders
const profile = useObservable({ name: '' })
// This runs whenever profile changes
useObserve(() => {
document.title = `${profile.name.get()} - Profile`
})
// Observe a single observable
useObserve(profile.name, (e) => {
document.title = `${e.value} - Profile`
})
// Observe an event
useObserve(eventUpdateTitle, (e) => {
document.title = `${profile.name.get()} - Profile`
})
return (
<div>
<span>Name:</span>
<Legend.input value$={profile.name} />
</div>
)
}
useObserveEffect
useObserveEffect
is the same as useObserve except that it doesn't run until the component is mounted.
useSelector
useSelector
computes a value and automatically listen to any observables accessed while running, and only re-renders if the computed value changes.
Props:
selector
: Observable or computation function that listens to observables accessed while running
import { observable } from "@legendapp/state"
import { useSelector } from "@legendapp/state/react"
const state = observable({ selected: 1, theme })
const Component = ({ id }) => {
// Only re-renders if the return value changes
const isSelected = useSelector(() => id === state.selected.get())
// Get the raw value of an observable and listen to it
const theme = useSelector(state.theme)
...
}
useObservableReducer
useObservableReducer
works the same way as useReducer
but sets an observable rather than triggering a render.
import { useObservableReducer } from "@legendapp/state/react"
const Component = () => {
// Only re-renders if the return value changes
const isSelected = useObservableReducer()
// Get the value of the reducer
const theme = isSelected.get()
...
}