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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tmas45/zustand-message-store

v1.0.0

Published

A message store implementation using Zustand

Readme

Visivi 4 Message passing system

Within Visivi4 there are multiple cases when an interaction somewhere in the app could require the display of user-facing "messages". This module provides a method for which that can be attained.

Module break-down:

The message system is made up of four main parts:

  • The store: Where the messages and the associated mutation functions are located.
  • The rendering components: Components which are used to display the various messages.
  • The hooks: Hooks to assist with accessing the message store.
  • The context: React context to provide the message service to multiple parts of the app.

The store

The message store is a zustand store which primarily stores the current set of messages that are to be displayed. Along with the messages, it also hosts a collection of mutators and getters to make interacting with the store easier.

The message model is split into two types:

  • Simple messages: Ones which are text-based and whose contents are rendered in a standard way for each simple message
  • Component messages: Ones whose main constituent is another React component, allowing for a more complex display.

The rendering components

The rendering components provide a method in which to display the messages in a standard way. This makes use of the context and the store to display any existing messages within a given container.

You can place the MessageOutlet component at any point in the app as long as it has access to a MessageContext. It is suggested to put this as high up in the DOM as possible as to maximise the coverage of the MessageContext.

The hooks

To make using the message store easier, a set of hooks are provided for both types of message:

These can be used in order to simplify interaction with the message store, and reduce the reliance on using useMessageStore(s => s.[...]).

The context

A React context is also defined to enable to passing of message stores to sub-components without the need to "prop-drill", and to avoid the default Zustand pattern of a global store. This makes it really easy to access the state within any component.

At the highest point in the app where messages are needed you can add the following:

const myComponent = () => {
    const messageStore = useCreateMessageStore();
    // ...

    return <MessageStoreContext value={messageStore.current}>
        <div>
            <InnerComponent/>
            {/*...*/}
        </div>
    </MessageStoreContext>
}

Message types

As mentioned before, there are two types of message:

  • Simple messages
  • Component messages

This section goes over, in detail, the two types, and provides examples on how best to use them:

Simple messages

Component messages

Component messages are inherently more complicated than their "simple" counterparts. To ensure type safety, these messages require the registering of their respective component's prop types. While this is optional, it significantly improves developer experience when dealing with complex components.

Registering components

For enhanced type safety you should register your message's component's props against the message's ID. Currently this limits the number of component messages with a given ID to just one, howver, in a lot of cases this is all that is required.

In order to register the props we make use of Typescript's name-space system:

type TestMessageComponentProps = {
    text: string,
    image: Uint8Array
}

const TestMessageComponent = (props: TestMessageComponentProps) => {
    // ...
}

// Register this component's props in the global registry
import "@themason45/zustand-message-store"

declare module "@themason45/zustand-message-store" {
    // noinspection JSUnusedGlobalSymbols This is used by the message library
    interface ComponentMessageRegistry {
        "test-component-message": MessageCompProps;
    }
}

This will ensure that when both pushing (creating), and updating a message, the prop types will have consistent and proper typing reducing the risk of errors.

Component-based message example:

An example making use of component-based messages assuming that a MessageContext has been provided above, and a MessageOutlet is present somewhere within that context:

type MessageCompProps = {
  name: string
  counter: number
}

const MessageComp: FunctionComponent<MessageCompProps> = ({name, counter}: MessageCompProps) => {
  return <div className={"p-4 bg-gray-200"}>THE MESSAGE: {name}. You have {counter} apples.</div>
}

// Register this component's props in the global registry
import "@themason45/zustand-message-store"

declare module "@themason45/zustand-message-store" {
  // noinspection JSUnusedGlobalSymbols This is used by the message library
  interface ComponentMessageRegistry {
    "test-component-message": MessageCompProps;
  }
}

export const InnerComponent = () => {
  const {pushMessage, updateMessage, destroyMessage} = useComponentMessageCRUD()

  /**
   An initial message creation function. You can pass this the actual component to
   render, along with its initial `prop`s.
   */
  const send = () => {
    pushMessage("test-message", {
      component: MessageComp,
      props: {
        name: "Initial",
        counter: 0
      }
    })
  }

  /**
   * An example mutation function. You may use these to update the props of the component.
   * Every update to this will re-render the message's component.
   */
  const increment = () => updateMessage("test-message", (props) => {
    props.counter++
    return props;
  })

  return <div className={"flex flex-col gap-2"}>
    <p>Hello, press <button onClick={() => send()}>here</button> to add message.</p>
    <p>Then press <button onClick={() => increment()}>here</button> to add some apples the message</p>
  </div>
}

The component outlet

The component outlet provides a place to display the messages that have been pushed to the message store.