Make Your React App Truly Reactive !


## Features ☢ Deeply Reactive, Directly Mutate State at any level to Update Component ⚡ Blazing Fast - 25% faster than `useState` 📺 No Extra Re-Renders - Auto Mutation batching 🌿 Always Fresh State, _unlike_ `useState` 🧬 Reactive Bindings For Inputs ⚛ Reactive Props ☕ Zero Dependencies, Ultra Light-Weight `< 1kb`
## 🌻 Motivation While the React's `useState` hook has been great for simple states, it is still **a pain to update a complex state**. It also comes with other problems like **not having the access to fresh state right away** after the new state is set and closure problems because of state's value only updating after a re-render. We can eliminate these problems, Improve performance and Introduce exciting new features in React with a **Truly Reactive State !** Enter `radioactive-state`
## Installation ```bash npm i radioactive-state ```
## ☢️ What's a Radioactive-State ? Radioactive state is a **deeply reactive** state. 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. No overhead of creating a new state at all! **Just mutate your state, that's it !**
## ✨ Creating a Radioactive State With `useRS` hook `radioactive-state` gives you a hook `useRS` (use radioactive state) which lets you create a radioactive state in your React Components. ### Examples > Click on the triangle icon to expand the Example
🍭 Counter App

Live Demo ```jsx import useRS from 'radioactive-state'; const Counter = () => { // create a radioactive state const state = useRS({ count: 0, }); // yep, that's it const increment = () => state.count++; return
{state.count}
; }; ```

---
🍡 Array Of Counters App

Let's take this a step further, Let's make an app that has an array of counters, each of them can be incremented individually and sum of all the counters is displayed too This examples shows that deep mutation also triggers a re-render and that **you can use any mutative functions directly** Live Demo ```jsx import useRS from "radioactive-state"; const Counters = () => { const state = useRS({ counts: [0], sum: 0 }); const increment = (i) => { state.counts[i]++; state.sum++; }; const addCounter = () => state.counts.push(0); return ( <>
{state.counts.map((count, i) => (
increment(i)} key={i}> {count}
))}
{state.sum}
); }; ```

## 📺 No Extra Re-Renders, Mutations are Batched You might be wondering: > "What if I mutate multiple keys in state, Is that going to trigger a re-render component multiple times ?" **Nope!** 😉 ### Example: ```js // suppose you are mutating multiple things in your state in a function doStuff 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); state.f = state.f.filter(x => x.completed); }; // When this function is called // it is not **not** going to trigger re-render of component 8 times 😉 // it will only trigger re-render 1 time! - No extra re-renders! 🤗 ``` #### How is that possible ? Mutations are batched into a one single mutation. So, No matter how many times you mutate the state, it only triggers re-render once This allows you to perform a complex mutation in multiple steps without having to worry about re-renders
Example ```javascript const addNewFriend = (newFriendID) => { const {users, userID} = state const user = users[userID] const newFriend = users[newFriendID] user.friends.push(newFriendID) newFriend.friends.push(userID) } ```

## ⚛ Reactive Props In traditional React, Props are considered immutable and mutating them does not trigger re-render. But When using radioactive-state, if you pass a piece of state as a prop to child component, this **child component has the capability to trigger a re-render in parent component** by mutating the prop ! This can be a **powerful feature**, where **you no longer have to pass functions as props to child component for triggering a re-render in parent component**, which also removes the need to memoize that function ### Example: Todos App Live Demo


## 🌿 State is always fresh ! Unlike `useState`, `useRS`'s state is always fresh #### What does that mean ? When you set a new state using `useState`'s setter function, it does not directly change the value of state. value of state is changed only after a re-render. This can cause some weird bugs. Let's see those problems and see how `radioactive-state` is immune to them. ---
useState's state is not always fresh
Let's add Logs before and after the state is set in our counter app. Live Demo ```js 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 (
{state.count}
); } // when increment is called, you would get the same before and after values // before: 0 // after: 0 // we are not getting the fresh state after it is updated, // we have to wait for the component to re-render ```
### `useRS` state is always fresh! `useRS`'s state is mutated directly by the user. So, **No need to wait for a re-render to get the fresh state**. With radioactive-state, You can use your state with confidence that whenever you use it, it's gonna be fresh ! 😙 Live Demo ```js 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 (
{state.count}
); } // works as expected 😄 ! ``` ---
---
useState's closure problem
Let's assume that increment function is async and before incrementing the value of count, we have to wait for some async task. Now guess what happens if you click the counter quickly 3 times? count is only going to increment to 1 instead of 3, even though increment function is called 3 times ! Live Demo ```js function App() { const [state, setState] = useState({ count: 0 }); // click the button 3 times quickly so increment will be called 3 times // but all three times, it will use the same old value of count const increment = async () => { await someAsyncTask(); setState({ count: state.count + 1 }); }; return (
{state.count}
); } ``` This happens because setCount keeps using old value of count until the component re-renders. This is because increment function "closes over" the count when it was defined. To fix this issue, you update the state using a function like this: ```js // passing new state instead of function that creates new state fixes this issue setCount(prevState => { return { count: prevState.count + 1 } }) ``` This gets awkward and complicated really fast as your state becomes more complex.
### `useRS` fixes this issue ! Live Demo If you click the button 3 times quickly, count will increment from 0 to 3. It works as expected 🙌 ```js function App() { const state = useRS({ count: 0 }); const increment = async () => { await someAsyncTask(); state.count++; // works as expected ! }; return (
{state.count}
); } ``` ---
---
## ⚡ Radioactive State is blazing fast ! `useRS` is **25% faster** than `useState` for an a fairly Complex React App. > This number is derived from an average of 100 performance tests where an array of 200 objects is rendered and various operations like adding, removing, re-ordering and mutations were done one after another. Note that, `useRS` **keeps getting faster and faster** compared to useState if you keep increasing the complexity of state, **even more than 25%** But, **for a simple web app**, both will have about the **same performance** where state of a component is not that complex. ### Why `useRS` is faster than `useState` ? In the case of `useState`, every time you want to update the state, you have to create a new state and call setter function with the new state. But, In the case of `radioactive-state` **you don't have to create a new state**, you just mutate the state and that's it. radioactive-state **does not create a new state** under the hood either. There are other optimizations as well, which makes sure no extra work is done, no extra re-renders are triggered.
## 🧬 Reactive bindings for inputs
You can create a controlled input the old way like this ### using the `useState` ```jsx const [input, setInput] = useState("type something"); setInput(e.target.value)} type='text' /> ``` ### using the `useRS` ```jsx // creating state const state = useRS({ input: '' }) state.input = e.target.value} type='text' /> ``` Both are fairly easy but becomes annoying if you have a form with multiple inputs You would also have to convert string to number if the input is type 'number' or 'range'. You would also need to use 'checked' prop instead of 'value' for checkboxes and radios ---

Radioactive State provides a binding API that lets you bind an input's value to a key in state. To bind `state.key` to an input you prefix the key with $ - `state.$key` and then spread over the input. that's it ! 😮 ```js ``` This works because, `state.key` returns the value but `state.$key` returns an object containing value and onChange props, which we are spreading over input
### Bindings takes care of different types of inputs Bindings **rely on initial value of the key** in state to figure out what type of input it is if the initial value is a type of `string` or `number`, `state.$key` returns object containing `value` and `onChange` If the initial value is type of `boolean`, `state.$key` returns an object containing `checked` and `onChange` props and uses `e.target.checked` internally in the onChange function If the initial value type of `number`, onChange function converts the `e.target.value` from `string` to `number` then saves it in the key. #### Example Live Demo

```jsx const state = useRS({ a: 69, b: 420, c: "Hello", d: "Write something here", e: true, f: "bar" }); const { $a, $b, $c, $d, $e, $f } = state; return (
 {JSON.stringify(state, null, 2)}