Reactive Props

Legend-State makes it easy to bind props directly to an observable or selector, so the component re-renders itself whenever the observable or selector changes without needing to re-render the parent or children.

Legend-State provides reactive versions of all intrinsic components. For every prop it adds another one ending with $ that accepts a selector (an observable or a function returning a value based on observables), and it automatically tracks it for changes and re-renders it.

Note: The reactive components are created on-demand because the Legend object is a Proxy, so you don't need to worry about a performance hit of creating every wrapped component upfront.

React

import { enableLegendStateReact, useObservable } from "@legendapp/state/react"
import { Legend } from "@legendapp/state/react-components"

enableLegendStateReact();

function Component() {
    const state = useObservable({ name: '', age: 18 })

    return (
        <div>
            // Reactive styling
            <Legend.div
                style$={() => ({
                    color: state.age.get() > 5 ? 'green' : 'red'
                })}
                className$={() => state.age.get() > 5 ? 'kid' : 'baby'}
            />
            // Reactive children
            <Legend.div children$={() => (
                <div>{state.age.get() > 5 ? <Kid /> : <Baby />}
            )} />

            // Two-way bind to inputs
            <Legend.textarea value$={state.name} />
            <Legend.select value$={state.age}>...</Legend.select>
            <Legend.input
                value$={state.name}
                className$={(value) => !value && "border-red-500"}
                style$={(value) => !value && { borderWidth: 1 }}
            />
        </div>
    )
}

React Native

import { View } from "react-native"
import { enableLegendStateReact, useObservable } from "@legendapp/state/react"
import { Legend } from "@legendapp/state/react-native-components"

enableLegendStateReact();

function Component() {
    const state = useObservable({ name: '', enabled: false })

    return (
        <View>
            // Reactive styling
            <Legend.Text
                style$={() => ({
                    color: state.enabled.get() ? 'green' : 'red'
                })}
            >
                {state.name}
            </Legend.Text>

            // Two-way bind to inputs
            <Legend.Switch value$={state.enabled} />
            <Legend.TextInput
                value$={state.name}
                style$={() => (state.name.get() === 'Legend' && { backgroundColor: 'green' })}
            />
        </View>
    )
}

Two-Way Binding to Inputs

If you pass an observable to the value$ prop of an input component, it sets up a two way binding that updates the observable automatically, so you don't have to worry about managing refs or onChange handlers.

import { enableLegendStateReact, useObservable } from "@legendapp/state/react"
import { Legend } from "@legendapp/state/react-components"

enableLegendStateReact();

function Component() {
    const state = useObservable({ name: 'Legend' })

    return (
        <div>
            <div>{state.name}</div>
            <Legend.input
                value$={state.name}
                className$={() =>
                    state.name.get() === 'Legend' ?
                        'text-white' :
                        'text-red-500'
                }
            />
        </div>
    )
}
Legend

Make external components reactive

You can wrap external components in reactive to add reactive versions of all of their props.

In this example we make a Framer Motion component reactive so that we can update its animations based on observables without needing to re-render the parent component or its children.

import { reactive } from "@legendapp/state/react"
import { motion } from "framer-motion"

const ReactiveMotionDiv = reactive(motion.div);

function Component() {
    const width = useObservable(100)

    return (
        <ReactiveMotionDiv
            animate$={() => ({
                x: width
            })}
        >
            ...
        </ReactiveMotionDiv>
    )
}

Make your own

You can just wrap your components in reactive if you'd like, but it's also easy to make specific parameters reactive. All it needs is a useSelector to make the prop reactive and get the raw value.

import { useSelector } from "@legendapp/state/react"

function MyComponent({ prop, prop$ }) {
    // Get the observable value if it exists or
    // otherwise get the normal prop value
    prop = useSelector(prop$ ?? prop)

    ...
}

See react-components on GitHub for the latest full source.