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

react-event-driven-store

v1.0.7

Published

`react-event-driven-store` is a lightweight and versatile state management solution for React applications, built around modularity, reactivity, and event-driven architecture. It provides developers with a simple yet powerful way to manage global state us

Downloads

516

Readme

React event driven store

react-event-driven-store is a lightweight and versatile state management solution for React applications, built around modularity, reactivity, and event-driven architecture. It provides developers with a simple yet powerful way to manage global state using React's Context API and custom hooks.

Designed to be intuitive and flexible, this library allows you to easily define, manipulate, and subscribe to state across your application. With a clear and consistent API, developers can organize state logic, dispatch mutations, and listen for updates—all while ensuring optimal performance. Whether you're building a small project or a complex app, react-event-driven-store offers a clean, efficient, and reactive approach to state management.

Installation

To install the react-event-driven-store package, run the following command:

npm install react-event-driven-store

Usage

Setting up the Store

To set up a store, wrap your app with the EventStoreProvider component. You can define modules that contain state, mutations (for state updates), and getters (for retrieving computed values). In this example, we're using a simple counter module.

import { EventStoreProvider, ModuleType } from "react-event-driven-store";

export const App = () => {
  return (
    <EventStoreProvider<[ModuleType<ICounter>]>
      modules={[
        {
          moduleName: "counter",
          state: {
            counter: 0,
          },
          mutation: {
            inc(value) {
              this.counter = this.counter + value.payload;
            },
            dec() {
              this.counter = this.counter - 1;
            },
          },
          getters: {
            getCounter() {
              return {
                counter: this.counter,
              };
            },
          },
        },
      ]}
    >
      {/* UI */}
    </EventStoreProvider>
  );
};

Using Mutations

In your components, you can utilize the useModuleMutation hook to interact with the state through mutations. Here’s an example of how to use the mutate function to dispatch actions to a module:

import { useModuleMutation } from "react-event-driven-store";

export const HomePage = () => {
  const { mutate } = useModuleMutation("counter");

  return (
    <>
      <button
        onClick={() =>
          mutate({
            payload: 1,
            event: "INC",
            commit: "inc",
          })
        }
      >
        Increment Counter
      </button>
    </>
  );
};

Using Module Selector

The useModuleSelector hook allows components to access specific data from your state modules and automatically subscribe to updates. This ensures that your component re-renders whenever the selected data changes. Here’s an example of how to use the useModuleSelector in a component:

import { useModuleSelector } from "react-event-driven-store";

const SomeComponent = () => {
  const { value } = useModuleSelector<{
    counter: number;
  }>({
    getterName: "getCounter",
    commit: ["INC"],
    moduleName: "counter",
  });

  let { counter } = value;
  console.log("*********", counter);

  return (
    <>
      <span>Counter Value: {counter}</span>
    </>
  );
};

export { SomeComponent };

In this example, the SomeComponent uses the useModuleSelector hook to access the counter value from the counter module. The getterName specifies which getter function to call, and the commit array defines which events the component should listen to for updates.

Important Note: If the commit array is empty (i.e., commit: []), the component will not re-render when the state changes. In this case, you will only receive the initial value from the store upon mounting the component.

Whenever the counter value is updated through a mutation (e.g., when the increment or decrement actions are dispatched), and the appropriate events are specified in the commit array, the component will automatically re-render with the latest counter value, providing a reactive and seamless experience.

Using SelectorItem

In the example below, we define a SomeComponent that utilizes the SelectorItem wrapper, which is essentially a higher-order component for the useModuleSelector hook. This component simplifies the process of selecting state from a specific module.

import { SelectorItem } from "react-event-driven-store";

const SomeComponent = () => {
  return (
    <>
      <span>SomeComponent</span>
      <SelectorItem<{
        counter: number;
      }>
        selectorConfig={{
          getterName: "getCounter",
          commit: ["INC"],
          moduleName: "counter",
        }}
      >
        {(value) => {
          console.log("value", value.counter);
          return <></>;
        }}
      </SelectorItem>
    </>
  );
};

export { SomeComponent };

Key Advantages of SelectorItem

The SelectorItem component acts as a wrapper around the useModuleSelector hook, accepting the same configuration interface. The main benefits of using SelectorItem include:

  • Encapsulation of Selector Logic: By encapsulating the selector logic within SelectorItem, it simplifies the component structure, making it easier to manage and maintain.

  • Reduced Re-renders: SelectorItem minimizes unnecessary re-renders by allowing updates to be localized only to specific parts of the UI that need to change in response to events. This leads to improved performance and a more efficient rendering process.

Event Emitter: Streamlined Component Communication

In modern applications, effective communication between components is crucial for maintaining a responsive and organized user interface. The Event Emitter pattern provides a powerful mechanism to facilitate this interaction without relying on shared state management.

Emitting Events

The SomeComponent illustrates how to use the useEmitEvent hook to broadcast events throughout your application. By clicking the button, it emits an event named EMIT_AGE, passing along relevant data (in this case, an age value of 50). This decouples the emitting component from any listeners, promoting a more modular design.

import { useEmitEvent } from "react-event-driven-store";

const SomeComponent = () => {
  const emitEvent = useEmitEvent();

  return (
    <>
      <span>SomeComponent</span>
      <button
        onClick={() =>
          emitEvent("EMIT_AGE", {
            age: 50,
          })
        }
      >
        Emit event
      </button>
    </>
  );
};

export { SomeComponent };
Listening for Events

On the other hand, the SomeComponentTwo showcases the use of the useOnEvent hook, which allows components to listen for specific events. In this example, it listens for the EMIT_AGE event and logs the data received when the event is emitted. This selective listening enhances performance by ensuring components only react to relevant changes.

import { useOnEvent } from "react-event-driven-store";

const SomeComponentTwo = () => {
  useOnEvent("EMIT_AGE", (data) => {
    console.log("on event", data);
  });
  return <></>;
};

export { SomeComponentTwo };

Key Benefits

  • Decoupled Communication: Components can interact without being tightly coupled to a shared state, leading to better maintainability.
  • Selective Listening: By allowing components to listen for specific events, you minimize unnecessary re-renders, improving application performance.
  • Enhanced Modularity: This approach promotes modular design, enabling components to be reused across different contexts without modifications. By incorporating the Event Emitter pattern, your application can achieve more dynamic and efficient component interactions, creating a seamless experience for users while simplifying your codebase.

Note on Selectors and Event Emitters

It's important to highlight that selectors, which rely on specific events triggered through mutations (using commit lists), will not be activated by events emitted via the Event Emitter pattern. This is because selectors are designed to respond to state changes managed through mutations, while event emitters facilitate direct communication between components without altering the application state.

Therefore, if you need components to reactively update based on certain state changes, ensure those updates are managed through the defined mutation mechanisms rather than the event emitter.

Key Benefits

  • Optimized Rendering: Components only re-render when the selected state changes, improving performance.
  • Cleaner Code: Reduces the need for boilerplate code for managing state subscriptions.
  • Ease of Use: Simple API that integrates seamlessly with your existing components.

Conclusion

The EventStateStoreProvider offers a robust and flexible approach to managing state, events, and reactivity across your React components. By utilizing its features, you can streamline communication, encapsulate logic, and minimize unnecessary re-renders.

Key takeaways include:
  • Encapsulation and Flexibility: With useModuleMutation and useModuleSelector, components can interact with the state in a modular and organized way, allowing for better code separation and flexibility. The mutation system ensures that changes are committed predictably, while selectors provide reactive access to state values.

  • Efficient Re-rendering: The SelectorItem component acts as a wrapper for selectors, encapsulating selector logic and allowing precise control over which UI parts re-render. This helps in optimizing performance by minimizing re-renders to only the relevant components.

  • Event-Driven Communication: The built-in event emitter (useEmitEvent and useOnEvent) allows components to communicate without altering the state, which is useful for scenarios where direct component-to-component interaction is required. However, note that selectors dependent on mutation-based events will not react to emitted events.

By combining state management and event-driven design, EventStateStoreProvider simplifies the architecture of complex applications, reduces boilerplate code, and enhances maintainability. It brings together a cohesive approach to managing state and events, providing developers with the tools needed to build responsive and scalable React applications.