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

hez

v1.0.54

Published

Flux architecture for React app. Fast and easy to use

Downloads

97

Readme

Hez

Flux architecture for React app. Fast and easy to use.

Hez requires React hooks, so you must install react 16.7+ and react-dom 16.7+ packages

Features

  1. No reducer
  2. No action creator
  3. Simple and reusable action logic
  4. Easy to write unit-test

Hez in action

  1. Compare to Redux https://codesandbox.io/s/53l6y55kmk

Counter app

import React from "react";
import ReactDOM from "react-dom";
import { createStore, useStore, useActions } from "./hez";

const initialState = {
  count: 0
};

const store = createStore(initialState);

const Up = (state, value) => state.set({ count: state.count + value });
const Down = (state, value) => state.set({ count: state.count - value });
const AddTen = state => Up(state, 10);

const App = () => {
  const count = useStore(store, state => state.count);
  const [up, down, addTen] = useActions(store, Up, Down, AddTen);

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={() => up(1)}>Up</button>
      <button onClick={() => down(1)}>Down</button>
      <button onClick={() => addTen()}>Add 10</button>
    </div>
  );
};

const rootElement = document.getElementById("hez-app");
ReactDOM.render(<App />, rootElement);

Create a store

import { createStore } from "hez";

const store = createStore({
  todos: []
});

Define an action

const AddTodo = (state, text) =>
  state.set({ ...state.get(), todos: state.todos.concat({ text }) });

Dispatch an action

import { useActions } from "hez";

const AddTodoForm = () => {
  const [addTodo] = useActions(store, AddTodo);

  function handleClick() {
    addTodo("new todo");
  }

  return <button onClick={handleClick}>Add Todo</button>;
};

Access state values

import { useStore } from "hez";

const TodoCount = () => {
  const count = useStore(store, state => state.todos.length);

  return <div>{count}</div>;
};

Async actions

const SaveTodos = state => {
  return axios({ url: "save.todo.api", data: state.todos }).then(
    () => alert("succeeded"),
    () => alert("failed")
  );
};

Reuse action logic

const AddOne = state => state.set({ value: state.value + 1 });
const AddTwo = state => {
  AddOne(state);
  AddOne(state);
};

Using state.set

const state = createState({ count: 0 });
state.set({ count: 1 }); // => 1
state.set("count", x => x + 1); // => 2
// state.set(prevState => nextState);

Using state.merge

const store = createStore({
  value1: 1,
  value2: 2
});

const Add1 = state =>
  state.set({
    ...state.get(),
    value1: state.value1 + 1
  });

// using merge will reduce your code
const Add2 = state =>
  state.merge({
    value2: state.value2 + 1
  });

// state.merge(prevState => nextState);

Using immhelper to update state

import update from "immhelper";
import { createState } from "hez";

const state = createState({ value1: 1, value2: 2, todos: [] });
state.set(
  update(state, {
    value1: ["set", 2],
    value2: ["set", 3],
    todos: ["push", "New Todo"]
  })
);

// shorthand
state.set(
  update({
    value1: ["set", 2],
    value2: ["set", 3],
    todos: ["push", "New Todo"]
  })
);

Printing state

import { createState } from "hez";

const state = createState({ count: 1 });
console.log(state); // => [[Proxy]]
console.log(state.get()); // => { count: 1 }

Access state props

import { createState } from "hez";

const state = createState({ count: 1 });
const { count } = state;
const count2 = state.count;
const count3 = state.get("count");
const count4 = state.get(x => x.count);

Dispatching action and handling state change

import { createStore } from "hez";

const store = createStore({ count: 0 });

const Up = (state, value = 1) => state.set("count", x => x + value);

// handle change
store.subscribe((state, e) => {
  console.log(state, e.action);
});

store.dispatch(Up); // => { count: 1 }, Up
store.dispatch(Up, 2); // => { count: 3 }, Up

Using useStore(store, selector, ...cacheKeys)

import React from "react";
import { createStore, useStore, withState } from "hez";

const store = createStore({
  todos: {
    1: "Item 1",
    2: "Item 2"
  }
});
const TodoItem = ({ id }) => {
  // component will re-render once state changed or received new id prop
  const text = useStore(store, state => state.todos[id], id);
  return <div>{text}</div>;
};

const TodoHoc = withState(
  store,
  (state, props) => ({
    text: state.todos[props.id]
  }),
  // cache key factory (optional) should return array
  props => [props.id]
);

const TodoItem = TodoHoc(props => <div>{props.text}</div>);

Using useStoreMemo(store, cacheKeysSelector, stateSelector, ...extraCacheKeys)

import React from "react";
import { createStore } from "hez";

const store = createStore({
  ids: [1, 2],
  todos: {
    1: { text: "Item 1" },
    2: { text: "Item 2" }
  }
});

// selector
const selectIds = state => state.ids;
const selectTodos = state => state.todos;
const selectTodoList = (ids, todos) => ids.map(id => ({ id, ...todos[id] }));

const TodoList = () => {
  const todos = useStoreMemo(store, [selectIds, selectTodos], selectTodoList);

  return <div>{JSON.stringify(todos)}</div>;
};

Using withActions

import React from "react";
import { withActions } from "hez";

const Up = () => {};
const Down = () => {};

const Counter = withActions(store, {
  up: Up,
  down: Down
})(({ up, down }) => (
  <div>
    <button onClick={up}>Up</button>
    <button onClick={down}>Down</button>
  </div>
));

Using Provider to pass down store to component tree

As many frameworks, hez also supports Provider to passing down store

import React from "react";
import { Provider, createStore, useStore } from "hez";

const store = createStore();

const Counter = () => {
  // dont need to call useStore(store, state => state.count);
  const count = useStore(state => state.count);
  return <div>{count}</div>;
};

const App = () => (
  <Provider store={store}>
    <Counter />
  </Provider>
);

State props injection

You can inject state utilize method by using store.inject

Using immhelper for updating state

import update from "immhelper";

const store = createStore({ todos: [] });

store.inject({
  update(state, ...args) {
    const { getState, setState, mergeState } = state;
    setState(update(getState(), ...args));
  }
});

const AddTodo = (state, text) => {
  state.update({
    todos: ["push", text]
  });
};

Using immer for updating state

import produce from "immer";

const store = createStore({ todos: [] });

store.inject({
  update(state, modifier) {
    const { getState, setState, mergeState } = state;
    setState(produce(getState(), modifier));
  }
});

const AddTodo = (state, text) => {
  state.update(draft => {
    draft.todos.push(text);
  });
};

Listen another action dispatching

We can add listener which will be called when specified action dispatched. Use to clean up something

const Login = state => {
  LoadProfile(state);
  LoadSettings(state);
};

const Logout = state => {};

const LoadProfile = state => {
  state.merge({
    profile: {}
  });

  state.on(Logout, CleanProfile);
};

const LoadSettings = state => {
  state.merge({
    settings: {}
  });

  state.on(Logout, CleanSettings);
};

const CleanProfile = state => {
  state.merge({
    profile: undefined
  });
};

const CleanSettings = state => {
  state.merge({
    settings: undefined
  });
};

Using reducer to update state

const state = createState({
  todos: []
});
const AddTodo1 = (state, text) => {
  state.reduce({
    todos: prev => [...prev, text]
  });
};

const AddTodo2 = (state, text) => {
  state.reduce(
    {
      todos: TodoReducers
    },
    {
      type: "add",
      payload: text
    }
  );
};

const TodoReducers = (state, action) => {
  if (action.type === "add") {
    return [...state, action.payload];
  }
  return state;
};

Unit Test

import { createState } from "hez";

const Add = ({ count, set }) => set({ count: count + 1 });

test("should increase count value by 1", () => {
  const state = createState({ count: 0 });
  Add(state);
  expect(state.count).toBe(1);
});

Todo App