react-rv is a lightweight and efficient state management library for React that allows you to create reactive variables and subscribe to them with minimal overhead.
npm install react-rv
pnpm add react-rv
yarn add react-rv
const isOnlineVar = rv(true)
const toggleStatus = () => isOnlineVar(!isOnlineVar())
const App = () => {
const isOnline = useRv(isOnlineVar)
return (
<div>
<h1>{isOnline ? 'You are online' : 'You are offline'}</h1>
<button onClick={toggleStatus}>Toggle Status</button>
</div>
)
}
const darkThemeVar = rv.fn(
() => {
try {
return JSON.parse(localStorage.getItem('darkTheme'))
} catch {
return false
}
},
{ on: val => localStorage.setItem('darkTheme', val) },
)
const toggleTheme = () => darkThemeVar(!darkThemeVar())
const Component = () => {
const isDarkTheme = useRv(darkTheme)
return (
<>
{isDarkTheme ? <...> : <...>}
<button onClick={toggleTheme}>Toggle</button>
</>
)
}
react-rv
Over React Context?rv()
function is already a getter/setter itself.// you need to provide non-sensical default setters in order to please TypeScript
// or manually cast the value into the correct type
const CountContext = React.createContext({ count: 0, setCount: () => {} })
const NameContext = React.createContext({ name: "John", setName: () => {} })
const App = () => {
// you need to use `useState` hook to manage getting/setting your state
const [count, setCount] = useState(0)
const [name, setName] = useState("John")
// With react context, you need to wrap the app into providers.
// Additionally, you need to provide "setters" for every state in case
// this state can be updated.
return (
<CountContext.Provider value={{ count, setCount }}>
<NameContext.Provider value={{ name, setName }}>
{/* uses CountContext */}
<Counter />
{/* uses NameContext */}
<NameDisplay />
</NameContext.Provider>
</CountContext.Provider>
)
}
const Counter = () => {
const { count, setCount } = useContext(CountContext)
// you can only define your own custom setters inside react component tree
// in order to get access to current state
const increment = () => setCount(count + 1)
return <button onClick={increment}>Count: {count}</button>;
}
// after you provide these default values, you don't need to set them again in any `useState` hook
const countVar = rv(0)
const nameVar = rv("John")
// there's no need to use provider components
const App = () => (
<>
{/* uses countVar */}
<Counter />
{/* uses nameVar */}
<NameDisplay />
</>
)
// you can define your own setters anywhere and you can still read the current state.
// calling a reactive variable with no arguments will return its current value, no matter where you are.
const increment = () => countVar(countVar() + 1)
const Counter = () => {
// whenever `countVar` value is updated, this hook will re-render this component
const count = useRv(countVar)
return <button onClick={increment}>Count: {count}</button>
}
MIT