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

reasy-state

v1.0.62

Published

reasy-state - A state management library for React

Downloads

1,111

Readme

Build Status Build Size Version Downloads

Reast Easy State

Reast Easy State is simple state management for React

Reasy-state allows you to easily work with your state without creating selectors or worrying about re-renders, by having each object or array element have its own hook for getting the value, get/set functions and mutators. It is also possible save state to storage to initialize the state in the server side component

Installation

To install the latest stable version, run the following command:

npm install reasy-state

Usage example

Create a state

Create state and export necessary functions

The function names will be generated automatically, depending on your object. ( get*, set*, use* and reset)

// store.ts

import { createState } from "reasy-state";

const userStore = {
    id: 1,
    name: "User Name",
    settings: {
        notification: true,
    },
};

export const {
    getUserStoreId,
    useUserStoreName,
    useUserStoreSettingsNotification,
    setUserStoreSettingsNotification,
    reset,
} = createState({ userStore });

Use exported functions in your components

// user.tsx

import { getUserStoreId, useUserStoreName, reset } from "./store";

const UserComponent = () => {
    const userName = useUserStoreName();

    return (
        <div>
            <p onClick={() => console.log("User ID:", getUserStoreId())}>
                {userName}
            </p>
            <button onClick={reset}>Reset store</button>
        </div>
    );
};
// setting.tsx

import {
    setUserStoreSettingsNotification,
    useUserStoreSettingsNotification,
} from "./store";

const SettingsNotificationComponent = () => {
    const checked = useUserStoreSettingsNotification();

    return (
        <input
            type="checkbox"
            checked={checked}
            onChange={() => setUserStoreSettingsNotification((prev) => !prev)}
        />
    );
};

Mutators

You can use mutators to export functions. You can also use closures and async functions inside mutators. Use a set or patch function that takes a new value, or a function that takes the old value as a parameter and returns a new value, to change the state of the current object in the state. set / patch will return you the new state of the object. Use a get function for async mutators, for get previous object value, or use second function argument

mutators: {
  [functionName]: ({set, patch, get}, previousValue) => ...
}
// store.ts
import { createState, CreateState } from "reasy-state";

type State = CreateState<{ value: number; mutators: { inc: void } }>;

export const { useValue, inc } = createState<State>({
    value: 1,
    mutators: {
        inc: ({ set }, { value }) => set({ value: value + 1 }),
    },
});
// page.tsx
import { useValue, inc } from "./store.ts";

export const Page = () => {
    const value = useValue();

    return (
        <>
            <div>value: {value}</div>
            <button onClick={() => inc()}>inc</button>
        </>
    );
};

Also, you can avoid specifying mutator types explicitly by using currying, and also use nested mutators

// store.ts
import { createState } from 'reasy-state';

type UserStore = {
  userStore: {
    id: number;
    data: {
      rating: number;
    };
  };
};

export const {
  userStoreDataClear,
  useUserStoreDataRating,
} = createState<UserStore>()({
  userStore: {
    id: 1,
    data: {
      rating: 1,
      mutators: {
        clear: ({ set }) => set({ rating: 0 }).rating, // return 0
      },
    },
  },
});

Async mutators

// store.ts
import { createState, CreateState } from "reasy-state";

type State = {
    value: number;
    mutators: {
        add: (value: number) => Promise<number>;
    };
};

const { useValue, add } = createState<State>()({
    value: 1,
    mutators: {
        add:
            ({ set, get }) =>
            async (addValue) => {
                await new Promise((f) => setTimeout(f, 1000));
                return set({ value: get().value + addValue }).value;
            },
    },
});
// page.tsx
import { useValue, inc } from "./store.ts";

export const Page = () => {
    const value = useValue();
    const onClick = () =>
          add(1).then((value) => console.log("new value = ", value));

    return (
        <>
            <div>value: {value}</div>
            <button onClick={onClick}>add async</button>
        </>
    );
};

Undefined params

You can use functions for undefined parameters using the $ sign

// store.ts
type UserStore = {
    id: number,
    data?: {
        rating: number,
    },
};
const userStore: CreateState<UserStore> = {
    id: 1,
};

export const { useUserStore$data$rating } = createState({ userStore });

Arrays

You can use arrays parameters functions using the $ sign

For array element set, get and use functions, you can use a filter to specify which elements you need to get or change

get`[...functionName]`(filterFunction?);
use`[...functionName]`(filterFunction?);
set`[...functionName]`(filterFunction, newValue);
// store.ts

type UserStore = {
    id: number,
    subscribers: {
        id: number,
        rating: number,
    }[],
};

const userStore: CreateState<UserStore> = {
    id: 1,
    subscribers: [
        { id: 2, rating: 10 },
        { id: 3, rating: 12 },
    ],
};

export const {
    useUserStoreSubscribers$rating,
    setUserStoreSubscribers$rating,
} = createState({ userStore });
export const Ratings = () => {
    const ratings = useUserStoreSubscribers$rating(({ rating }) => rating);

    const add = () =>
        setUserStoreSubscribers$rating(
            ({ id }) => id === 2,
            (prev) => prev + 1,
        );

    const clear = () => setUserStoreSubscribers$rating(() => true, 0);

    return (
        <div>
            <p>Positive ratings = {ratings.join(",")}</p>
            <button onClick={add}>Add rating for id 2</button>
            <button onClick={clear}>Clear rating for all</button>
        </div>
    );
};

Usage in ssr components :warning: (experemental)

You can initialize your state or part of it in a server component like this:

//store.ts
'use client';

import { createState } from 'reasy-state';

type Store = {
    user: {
        id: number;
        name: string;
    };
};

export const { use$user$id, get$user$id, ssr: { SSR$user } } = createState<Store>()();
//page.tsx
"use server";

export default async function ServerPage() {
    const data = await getUser("username"); // data = {id, name}
    return (
        <>
            <SSR$user value={data} />
            <ClientPage />
        </>
    );
}
"use client";

import { get$user$id, use$user$id } from "./store";

export const ClientPage = () => {
    const id = use$user$id();
    return <p>User id = {id}</p>;
};

Storage

You can save the state in the store( localStorage (default), sessionStorage ) To do this, specify a unique key and configure saving if necessary

    const { ... } = createState(
        { store: { value: "value" } },
        { key: "storage_state_1", storage: true }
    );

:warning: If SSR is used together with storage, the latter will be initialized only after the component is rendered to avoid hydration warning. To do this, specify the ssr: true parameter.

    const { ... } = createState(
        { store: { value: "value" } },
        { key: "storage_state_2", storage: true, ssr: true }
    );

If necessary, you can mutate the data on read and write like this (This can be useful when using momentjs for example):

    const store = { id: 1, date: moment() };

    const { ... } = createState(
        { store },
        {
            key: "session_storage_date_1",
            storage: {
                type: sessionStorage,
                mutators: {
                    store: {
                        date: (mutate) =>
                            mutate({
                                put: (prev) => prev.toISOString(),
                                get: (prev) => moment(prev),
                            }),
                    },
                },
            },
        },
    );