What is Reactive?
⚛️ Reactive is a library that provides state management capabilities for JavaScript applications, intuitive, flexible, and written in TypeScript.
- 😊 Beginner-Friendly: Covered more than 80% of use cases with the create method.
- 🧩 Flexible Usage: Want to change the stored state? Just modify it anytime, anywhere through mutate.
- ⚡️ Performance Optimization: Utilizes the Proxy API to provide the best possible performance.
- 🏄 Framework Agnostic: Works well both in React and Vanilla JavaScript.
- 🦄 TypeScript Support: Written in TypeScript, fully typed for a better development experience.
- 🛠️ DevTools Integration: Out-of-the-box compatibility with Redux DevTools.
React Usage Example
Here's a simple example of using Reactive in a React application.
import { create } from '@shined/reactive'
const store = create({ count: 1 })
const addOne = () => store.mutate.count++
function App() {
const count = store.useSnapshot((s) => s.count)
return (
<div>
<p>Count is {count}</p>
<button onClick={addOne}>Increase</button>
</div>
)
}
For more information, please refer to React Usage or API Reference.
Try It Online
You can try Reactive online on CodeSandbox.
Free Mutation, Safe Consumption
Reactive adopts a read-write separation strategy, offering a more intuitive way of changing states through the store.mutate object. Simply modify the store.mutate
object when you need to change states!
export const store = create({
count: 1,
user: { name: 'Bob' }
})
export function increment() {
store.mutate.count++
}
export function updateUser() {
store.mutate.user = { name: 'Alice' }
}
For consumption, it provides a simple method to access the state through React's store.useSnapshot and the pure JavaScript/TypeScript's store.snapshot, ensuring safety. This method generates a non-expandable snapshot state to prevent accidental modifications.
// In React components
const { count } = store.useSnapshot()
const count = store.useSnapshot((s) => s.count)
// In Vanilla JavaScript/TypeScript
const { count } = store.snapshot()
const count = store.snapshot(s => s.count)
Optional Rendering Optimization
Moreover, Reactive also provides an optional rendering optimization feature.
// Only re-renders when `count` changes, `s => s.count` is the selector, used to pick the specified state.
const count = store.useSnapshot((s) => s.count)
You can use selector
to specify the state you want to pick, which will only re-render when the specified state changes. By default, components using the full snapshot will trigger a re-render whenever any part of the state changes.
Hint
For the design of the selector
API, and why the "automatic dependency collection" approach was abandoned, refer to proxy-compare
's issue#65.
A more comprehensive example of selector
:
import { create } from '@shined/reactive'
const store = create({
name: 'Bob',
age: 18,
hobbies: ['Swimming', 'Running'],
address: { city: { name: 'New York' } },
})
export default function App() {
// Will trigger re-render when any part of the store changes
const state = store.useSnapshot()
// Only re-renders when the `city` object in store changes
const { name: cityName } = store.useSnapshot((s) => s.address.city)
// Only re-renders when the `hobbies` object and `age` property in store change
const [hobbies, age] = store.useSnapshot((s) => [s.hobbies, s.age] as const)
// Only re-renders when the `name` in store changes
const name = store.useSnapshot((s) => s.name)
}