Radioactive State

JavaScript proxy based reactive state management library for React

Radioactive state library creates a reactive state for React. When it is mutated at any level (shallow or deep) it re-renders the component automatically. No need to set the state, no need to use libraries like immer.js to produce a new state - just mutate your state, that's it!

  • Deeply Reactive - mutate state at any level to update
  • No extra re-renders - auto mutation batching
  • Always fresh state, unlike useState
  • Reactive bindings for inputs
  • Zero dependencies, ultra light-weight < 1kb

Mutate to trigger re-render

Create a radioactive state with useRS and just mutate it to trigger re-renders.

import useRS from "radioactive-state";

const Counter = () => {
  const state = useRS({ count: 0 });

  // just mutate it!
  const increment = () => state.count++;

  return <div onClick={increment}>{state.count}</div>;
};

Mutation Batching

Mutations are batched into a single update. No matter how many times you mutate the state, it only triggers one re-render.

const doStuff = () => {
  state.a = 200;
  state.b.x.y.push([10, 20, 30]);
  state.c++;
  state.c++;
  state.c++;
  delete state.d.e.f;
  state.e.splice(10, 1);
};

// all these mutations trigger only 1 re-render!

Reactive Bindings

Bind inputs to state with state.$key syntax. It handles value, onChange, and type conversions automatically.

const state = useRS({
  name: "",
  age: 0,
  agreed: false
});

// spread $key to bind input to state
<input {...state.$name} type="text" />
<input {...state.$age} type="number" />
<input {...state.$agreed} type="checkbox" />

Always Fresh State

With useState, the state value only updates after a re-render.

function App() {
  const [state, setState] = useState({ count: 0 });

  const increment = () => {
    console.log("before:", state.count); // before: 0
    setState({ count: state.count + 1 });
    console.log("after:", state.count); // after: 0
  };

  return <div onClick={increment}>{state.count}</div>;
}

With useRS, state is mutated directly

function App() {
  const state = useRS({ count: 0 });

  const increment = () => {
    console.log("before:", state.count); // before: 0
    state.count++;
    console.log("after:", state.count); // after: 1
  };

  return <div onClick={increment}>{state.count}</div>;
}

Demos