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-imperator

v2.0.2

Published

State handler for React

Downloads

27

Readme

react-imperator 2.0

This is a state container that automatically (more or less) injects updated properties into connected components. Starting with 2.0, the architecture is rewritten to be more helpful and automagic. Please note that 2.0 is not backwards compatible with 1.0, though it shouldn't be overly hard to convert.

The package exposes a single method:

CreateStore

function createStore<StoreState>(initialState: StoreState)

This method is responsible for creating the initial store based on the supplied value, and then exposing the following methods:

Subscribe

subscribe<T extends StoreProp>(context: T, callback: Callback<T>): string

subscribe is mainly used for services, a component would normally not depend on it. It takes the following arguments:

  • a type argument extending StoreProp (which in turn is an alias for keyof StoreState)
  • a context of type T
  • a callback accepting a parameter of type StoreState[T]

The method returns a randomly generated name, which can be used to cancel a subscription

Unsubscribe

unsubscribe(name: string): void

unsubscribe is the reverse of subscribe, and removes all subscriptions of a specified name.

Get

get<T extends StoreProp>(context: T): StoreState[T]

get accepts a context of type T, and returns its current value. This is mainly used for components and services that don't necessarily want to subscribe to a specific context, but still might require its value

Update

update<T extends StoreProp>(context: T, reducer: (state: StoreState[T]) => StoreState[T]): void

update takes two arguments:

  • A context to update
  • A callback that receives the current state of the context, and is expected to return the new state

Connect

connect<LocalState>(Component: React.ComponentType<LocalState>, mapStoreToLocal: (state: StoreState) => LocalState): React.ComponentType<LocalState>

connect takes two arguments:

  • A component, may be stateless or stateful
  • A callback used to derive local state from the global state

Simple example

State.ts

import { createStore } from "react-imperator";

export interface IListState {
    items: IListItem[];
    text: string;
}

export interface IListItem {
    text: string;
    done: boolean;
    id: number;
}

export type StateMap<StoreState, LocalState> = (
    state: StoreState
) => LocalState;

export const { connect, get, update } = createStore<IListState>({
    items: [],
    text: ""
});

ListItems.tsx

import * as React from "react";
import { IListState, StateMap, connect, IListItem, update } from "./State";
import { AddItem } from "./AddItem";

interface IListItemsProps {
    list: IListItem[];
    text?: string;
}

const stateMap: StateMap<IListState, IListItemsProps> = (
    state: IListState
) => ({
    list: state.items || [],
    text: state.text
});

const handleToggle = (id: number) => (
    e: React.SyntheticEvent<HTMLInputElement>
) => {
    update("items", items =>
        items.map(item => {
            return item.id === id
                ? { ...item, ...{ done: e.currentTarget.checked } }
                : item;
        })
    );
};

export const ListItems = connect<IListItemsProps>(
    (props: IListItemsProps) => {
        return (
            <div>
                <ul>
                    {props.list.map(item => (
                        <li key={item.id}>
                            <input
                                type="checkbox"
                                checked={item.done}
                                onChange={handleToggle(item.id)}
                            />
                            {item.text}
                        </li>
                    ))}
                    <li>
                        <AddItem text="" />
                    </li>
                </ul>
            </div>
        );
    },
    stateMap
);

AddItem.tsx

import * as React from "react";
import { update, StateMap, IListState, connect } from "./State";

interface IAddItemProps {
    text: string;
}

const stateMap: StateMap<IListState, IAddItemProps> = (state: IListState) => ({
    text: state.text
});

export const AddItem : React.ComponentType<IAddItemProps> = connect(class extends React.Component<IAddItemProps, {}> {

    handleInput = (e: React.KeyboardEvent) => {
        if(e.which !== 13 || !this.props.text) {
            return;
        }

        this.handleAdd();
    }
    handleTextChange = (e: React.SyntheticEvent<HTMLInputElement>) => {
        update("text", () => e.currentTarget.value);
    }

    handleAdd = () => {
        update("items", state => [...state, { text: this.props.text, done: false, id: state.length + 1 }]);
        update("text", () => "");
    }

    render(): JSX.Element {
        return (
            <div>
                <div>
                    <input value={this.props.text || ""} onChange={this.handleTextChange} onKeyDown={this.handleInput} />
                    <button onClick={this.handleAdd}>Add</button>
                </div>
            </div>
        );
    }
}, stateMap);

react-imperator 1.0

This is a state container that automatically (more or less) injects updated properties into connected components.

The package exposes two methods, connect and update.

Connect

connect: <S>(Component: React.ComponentType<S>, contexts?: string[], excludedContexts?: string[]) => React.ComponentType<S>;

connect() takes three arguments:

  • A component, may be stateless or stateful
  • A list of contexts to force subscription (optional)
    • This is useful when you want to declare a property as optional, yet still want to add a subscription
  • A list of contexts to ignore (optional)

and returns a wrapped component

Update

update: <T>(context: string, producer: (state: T) => T) => void;

update() takes two arguments:

  • A context to update
  • A callback that receives the current state of the context, and is expected to return the new state

Simple example

ShowCount.tsx - Subscribes to the context "count", explicitly specified

import * as React from "react";
import { connect } from "react-imperator";

export const ShowCount = connect((props: { count?: number}) => <div>{props.count || 0}</div>, ["count"]);

Incrementer.tsx - Will update the context "count"

import * as React from "react";
import { update } from "react-imperator";

const click = () => {
    update<number>("count", value => (value || 0) + 1)
}

export const Incrementer = () => <button onClick={click}>Click me</button>;

New in 1.0.11

Imperator now exposes two additional methods:

subscribe: function<T>(context: string, callback: (state: T) => void): string;
unsubscribe: function(name: string): void;

These are helper methods to allow service classes and similar to monitor context changes. subscribe() takes two arguments:

  • A context to monitor
  • A callback to invoke when context changes And returns a random identifier for a subscription

unsubscribe() takes a single argument:

  • The subscription name to revoke (output from subscribe method)