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)
}