The custom emittor approach for state management in React offers a convenient way to manage and share states across multiple components without the need to wrap them with providers. By utilizing event-driven architecture, this method simplifies the handling of state updates, making it easy to work with event handlers and propagate changes throughout the application. With this approach, components can subscribe to state changes directly, ensuring seamless communication and synchronization between different parts of the UI. Additionally, it eliminates the boilerplate code associated with provider-based state management solutions, providing a more lightweight and flexible alternative for managing application state.
Install the package with npm:
npm install emittor
or yarn:
yarn add emittor
or pnpm:
pnpm add emittor
First Create Emittor
in separate file /lib/emittor.ts
import { createEmittor } from 'emittor'
export const countEmittor = createEmittor(0)
then:
connect State with Emittor
in client Components
"use client";
import { countEmittor } from "./lib/emittor";
function Page() {
// connect State with `Emittor` in client Components and use like useState Hook
const [count, setCount] = useEmittor(countEmittor)
...
}
This adjusted code snippet provides a simple and easy-to-understand usage example of the emittor
package. It demonstrates using the useEmittor
hook to manage state, similar to how useState
is used in React.
Warning
Always create an emittor in a separate file
Because in development mode, the whole file will be rendered again. That can cause unexpected bugs.
The emittor package enables automatic state synchronization across React components. By simply integrating emittor, any component subscribing to state changes will update whenever the state changes anywhere in the application. This eliminates the need for manual state passing or provider wrapping, streamlining development and enhancing component responsiveness.
import { useEmittor } from "emittor"
import { countEmittor } from "./lib/emittor"
function Page(){
return(
<>
<View />
<Button/>
</>
)
}
// This component only re-renders when the state is changed.
function View(){
const [count, setCount] = useEmittor(countEmittor)
return(
<div>
{count}
</div>
)
}
function Button() {
return (
<button onClick={()=>countEmittor.setState(countEmittor.state+1)}>Add</button>
)
}
export default Page
You can also use the emitter in event listeners or other functions to modify state.
countEmittor.getState()
countEmittor.setState(10)
// also use use directly
countEmittor.state
countEmittor.state = 10
It will re-render those components where that emitter is used.
First Create ReducerEmittor
in separate file /lib/emittor.ts
import { createReducerEmittor } from "emittor"
export const countREmittor = createReducerEmittor(0, {
increment: e=> {
e.setState(e.state+1)
},
decrement: e=> {
e.setState(e.state-1)
}
})
then use like this
"use client";
import { useEmittor } from "emittor"
import { countREmittor } from "./lib/emittor";
export default function Page() {
const [count, setCount] = useEmittor(countREmittor)
return (
<div className="flex gap-8">
<button className="bg-slate-700 p-3">
{count}
</button>
<button className="bg-slate-700 p-3" onClick={()=>countREmittor.reducers.increment()}>
+
</button>
<button className="bg-slate-700 p-3" onClick={()=>countREmittor.reducers.decrement()}>
-
</button>
</div>
);
}
you can also use Emittor
like ReducerEmittor
in /lib/emittor.ts
import { createEmittor } from "emittor"
const emittor = createEmittor(0)
function increment(by:number){
emittor.setState(emittor.state+by)
}
function decrement(by:number){
emittor.setState(emittor.state-by)
}
export const countEmittor = {
emittor,
increment,
decrement
}
use in Component
"use client";
import { useEmittor } from "emittor"
import { countEmittor } from "./lib/emittor";
export default function Page() {
const [count, setCount] = useEmittor(countEmittor.emittor)
return (
<div className="flex gap-8">
<button className="bg-slate-700 p-3" onClick={()=>setCount(count+1)}>
{count}
</button>
<button className="bg-slate-700 p-3" onClick={()=>countEmittor.increment(10)}>
+
</button>
<button className="bg-slate-700 p-3" onClick={()=>countEmittor.decrement(5)}>
-
</button>
</div>
);
}
Method | Description |
---|---|
constructor(initialState: T, options: { match?: boolean }) |
Initializes an instance of Emittor with an initial state and optional matching behavior. If options.match is true, setMatchState and emit are bound to handle state updates; otherwise, setOnlyState and emit are used. |
setState() , emit() |
Sets the state and Executes all subscribed callbacks (also use state ) |
getState() |
Returns the current state (also use state ). |
state |
Is current state (with get & set ) you can modify directly. |
exec() , refresh() |
Executes all subscribed callbacks with the current state. |
run(state: T) |
Executes all callbacks with the provided state (this will not changed current state). |
connect(callback: Callback<T>) |
Adds the callback to the list of callbacks to be executed on state changes. |
disconnect(callback: Callback<T>) |
Removes the specified callback from the list of callbacks. |
*setOnlyState(state: T) |
Updates the state without checking and executes all subscribed callbacks. |
*setMatchState(state: T) |
Updates the state only if the new state differs from the current state and then executes setOnlyState(state) . |
This project is licensed under the βΉοΈ MIT
License.