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

hookex

v0.0.22

Published

A simple state manager for React

Downloads

37

Readme

hookex

A state manager for React without reducer, Provider, dispatcher etc. Design for large projects which has thousand of components.

  1. No Provider needed
  2. No Store needed
  3. No Reducer needed
  4. No Action Creator needed
  5. No Dispatcher needed
  6. Simple concept: State & Action
  7. Support Simple State (Synchronous State)
  8. Support Asynchronous State (with debouncing)
  9. Support Dynamic State

Samples

Counter App

import React from "react";
import { render } from "react-dom";
import { createState, createAction, useStates } from "hookex";

// define CountState with 1 as default value
const CountState = createState(1);
// define an action, specified CountState as dependencies
// action body receives CountState accessor
// using count() to get current state value and count(newValue) to update state
const Increase = createAction([CountState], count => count(count() + 1));

function App() {
  const [count] = useStates(CountState);
  return (
    <div>
      Counter: {count}
      <button onClick={Increase}>Click to increase counter</button>
    </div>
  );
}

render(<App />, document.getElementById("root"));

Dynamic State

Create dynamic state which is computed from other states

import React from "react";
import { render } from "react-dom";
import { createState, createAction, useStates } from "hookex";

const CountState = createState(1);
const DoubleCountState = createState([CountState], count => count * 2, { sync: true });
const Increase = createAction([CountState], count => count(count() + 1));

function App() {
  const [count, doubleCount] = useStates(CountState, DoubleCountState);
  return (
    <div>
      <p>Counter: {count}</p>
      <p>Double Counter: {doubleCount}</p>
      <button onClick={Increase}>Click to increase counter</button>
    </div>
  );
}

render(<App />, document.getElementById("root"));

Async State

Search github user

import React from "react";
import { render } from "react-dom";
import { createState, createAction, useStates } from "hookex";

const apiUrl = "https://api.github.com/users/";
const SearchTermState = createState("");
const UpdateSearchTerm = createAction([SearchTermState], (searchTerm, value) =>
  searchTerm(value)
);
// once searchTerm changed, UserInfo state will be recomputed
const UserInfoState = createState([SearchTermState], async searchTerm => {
  const res = await fetch(apiUrl + searchTerm);
  return await res.json();
});

function App() {
  const [searchTerm, userInfo] = useStates(SearchTermState, UserInfoState);
  const { value, done } = userInfo;
  return (
    <div>
      <input
        type="text"
        value={searchTerm}
        onChange={e => UpdateSearchTerm(e.target.value)}
      />
      <pre>{done ? JSON.stringify(value, null, 2) : "Searching..."}</pre>
    </div>
  );
}

render(<App />, document.getElementById("root"));

Using AsyncRender component

AsyncRender component receives specified async state (or multiple states). When state loaded, render callback/component will be called unless AsyncRender's children will be rendered instead

import React from "react";
import { render } from "react-dom";
import { createState, createAction, useStates, AsyncRender } from "./hookex";

const apiUrl = "https://api.github.com/users/";
const SearchTermState = createState("");
const UpdateSearchTerm = createAction([SearchTermState], (searchTerm, value) =>
  searchTerm(value)
);
const UserInfoState = createState([SearchTermState], async searchTerm => {
  const res = await fetch(apiUrl + searchTerm);
  return await res.json();
});

function UserInfo({ data }) {
  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

function App() {
  const [searchTerm] = useStates(SearchTermState);

  return (
    <div>
      <p>
        <input
          type="text"
          value={searchTerm}
          onChange={e => UpdateSearchTerm(e.target.value)}
        />
      </p>
      <AsyncRender render={UserInfo} state={UserInfoState}>
        Loading...
      </AsyncRender>
    </div>
  );
}

render(<App />, document.getElementById("root"));

Saving and loading states with localStorage

import { createState, createAction, persist } from "hookex";

const CounterState = createState(1);
const Increase = createAction([CounterState], async counter =>
  console.log(counter(counter() + 1))
);

setInterval(Increase, 3000);

persist(
  {
    counter: CounterState
  },
  JSON.parse(localStorage.getItem("counterApp")) || {},
  state => localStorage.setItem("counterApp", JSON.stringify(state))
);

Update single state

Note: Cannot update computed state

import { createState } from "hookex";

const CounterState = createState(1);

setInterval(
  () =>
    CounterState(prev => {
      console.log(prev);
      return prev + 1;
    }),
  3000
);

Using State as event handler

You can pass state to element event, it can process input synthetic event (event.target.value/event.target.checked)

import React from "react";
import { render } from "react-dom";
import { createState, useStates } from "hookex";

const ValueState = createState("Hello world !!!");
const CheckedState = createState(true);

function App() {
  const [value, checked] = useStates(ValueState, CheckedState);

  return (
    <>
      <p>
        <input value={value} onChange={ValueState} />
      </p>
      <p>{value}</p>
      <p>
        <input type="checkbox" checked={checked} onChange={CheckedState} />
      </p>
      <p>{checked ? "checked" : "unchecked"}</p>
    </>
  );
}

render(<App />, document.getElementById("root"));