Skip to content

Commit da6c282

Browse files
authored
docs: fills readme file
1 parent 475c2b2 commit da6c282

File tree

1 file changed

+181
-0
lines changed

1 file changed

+181
-0
lines changed

readme.md

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# react-rv
2+
3+
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.
4+
5+
## Features
6+
7+
- **Tiny**: No dependencies, minimal API surface.
8+
- **Easier than React Context**: More efficient updates without unnecessary re-renders.
9+
- **Efficient**: Only re-renders components that are subscribed to reactive variables.
10+
- **Flexible**: Works inside and outside React components.
11+
- **Custom equality checks**: Define your own comparison logic to avoid redundant updates.
12+
- **TypeScript Support**: Fully typed for better developer experience.
13+
14+
## Installation
15+
16+
### npm
17+
18+
```sh
19+
npm install react-rv
20+
```
21+
22+
### pnpm
23+
24+
```sh
25+
pnpm add react-rv
26+
```
27+
28+
### yarn
29+
30+
```sh
31+
yarn add react-rv
32+
```
33+
34+
## API and Usage
35+
36+
### `rv<T>(initialValue: T, options?: RvOptions<T>): Rv<T>`
37+
38+
Creates a new reactive variable.
39+
40+
#### Usage:
41+
```ts
42+
const state = rv(0)
43+
// calling variable with no arguments will return its current value
44+
console.log(state()) // 0
45+
// calling variable with an argument will set its value to this argument
46+
state(10)
47+
console.log(state()) // 10
48+
```
49+
50+
#### Options:
51+
52+
```ts
53+
const state = rv(0, { eq: (oldValue, newValue) => Math.abs(oldValue - newValue) < 0.01 })
54+
state(0.005) // Won't trigger an update because the values are "equal" under this custom rule.
55+
state(0.005, {
56+
// you can disable initial `eq` function by pasing false here
57+
// it will use a default `eq` function which is just a strict check: `===`
58+
// in this case, update WILL happen
59+
eq: false
60+
})
61+
state(0.005, {
62+
// you can override initial `eq` function by passing another one just for this update call
63+
eq: (oldValue, newValue): boolean => false
64+
})
65+
```
66+
67+
### `rv.on(listener: (value: T) => void): CleanupFn`
68+
69+
Subscribes to changes of the reactive variable.
70+
71+
#### Usage:
72+
73+
```ts
74+
const state = rv(0)
75+
const unsubscribe = state.on(value => console.log('New value:', value))
76+
state(1) // Logs: New value: 1
77+
unsubscribe()
78+
state(2) // No logs
79+
```
80+
81+
### `useRv<T>(rv: Rv<T>): T`
82+
83+
Subscribes to changes of the reactive variable inside a react component and updates it when the state is updated.
84+
85+
```tsx
86+
import React from 'react'
87+
import { rv, useRv } from 'react-rv'
88+
89+
const counter = rv(0)
90+
91+
const Counter = () => {
92+
const value = useRv(counter)
93+
return (
94+
<div>
95+
<p>Count: {value}</p>
96+
<button onClick={() => counter(value + 1)}>Increment</button>
97+
</div>
98+
)
99+
}
100+
```
101+
102+
## Why `react-rv` Over React Context?
103+
104+
- **More granual state splitting**: React Context would require to create a separate context for every piece of state you'd use, which would also force you to wrap the app with providers for each react context.
105+
If you don't do that and decide to create one big state, it would involve unnecessary re-renders in components that only need one field of the state.
106+
- **Simpler API**: No need for providers, reducers, or complex state logic.
107+
- **No need for state setters**: The variable that's returned by `rv()` function is already a getter/setter itself.
108+
- **Usage outside React component tree**: Since the variable itself is a setter as well, you can use it outside react component tree. For example in your util functions that's defined outside react components.
109+
110+
#### React Context example
111+
112+
```tsx
113+
// you need to provide non-sensical default setters in order to please TypeScript
114+
// or manually cast the value into the correct type
115+
const CountContext = React.createContext({ count: 0, setCount: () => {} })
116+
const NameContext = React.createContext({ name: "John", setName: () => {} })
117+
118+
const App = () => {
119+
// you need to use `useState` hook to manage getting/setting your state
120+
const [count, setCount] = useState(0)
121+
const [name, setName] = useState("John")
122+
123+
// With react context, you need to wrap the app into providers.
124+
// Additionally, you need to provide "setters" for every state in case
125+
// this state can be updated.
126+
return (
127+
<CountContext.Provider value={{ count, setCount }}>
128+
<NameContext.Provider value={{ name, setName }}>
129+
{/* uses CountContext */}
130+
<Counter />
131+
{/* uses NameContext */}
132+
<NameDisplay />
133+
</NameContext.Provider>
134+
</CountContext.Provider>
135+
)
136+
}
137+
138+
const Counter = () => {
139+
const { count, setCount } = useContext(CountContext)
140+
141+
// you can only define your own custom setters inside react component tree
142+
// in order to get access to current state
143+
const increment = () => setCount(count + 1)
144+
145+
return <button onClick={increment}>Count: {count}</button>;
146+
}
147+
```
148+
149+
#### react-rv example
150+
151+
```tsx
152+
// after you provide these default values, you don't need to set them again in any `useState` hook
153+
const countVar = rv(0)
154+
const nameVar = rv("John")
155+
156+
// there's no need to use provider components
157+
const App = () => (
158+
<>
159+
{/* uses countVar */}
160+
<Counter />
161+
{/* uses nameVar */}
162+
<NameDisplay />
163+
</>
164+
)
165+
166+
// you can define your own setters anywhere and you can still read the current state.
167+
// calling a reactive variable with no arguments will return its current value, no matter where you are.
168+
const increment = () => countVar(countVar() + 1)
169+
170+
const Counter = () => {
171+
// whenever `countVar` value is updated, this hook will re-render this component
172+
const count = useRv(countVar)
173+
174+
return <button onClick={increment}>Count: {count}</button>;
175+
}
176+
```
177+
178+
## License
179+
180+
MIT
181+

0 commit comments

Comments
 (0)