npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

emittor

v0.1.0

Published

State Management using custom hook without Wrapping components using Providers

Downloads

103

Readme

Next.js React TypeScript

git-last-commit GitHub commit activity GitHub top language

minified size

NPM Version GitHub


📍 Overview

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.


🚀 Getting Started

Install the package with npm:

npm install emittor

or yarn:

yarn add emittor

or pnpm:

pnpm add emittor

📖 Usage

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.

Emittor In Multiple Components

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

Other Usage

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.

Usage of ReducerEmittor

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


API Reference

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

📄 License

This project is licensed under the ℹ️ MIT License.