Skip to content

linq2js/hookex

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hookex

A state manager for React without reducer, Provider, dispatcher etc. Design for large projects.

  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
  10. Support Sub State
  11. Built-in methods for updating state on the fly
  12. Compatible with other state mangers (MobX, Redux...)

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"));

API References

  1. createState(defaultValue)
  2. createState(dependencies, functor, options)
  3. createAction(dependencies, functor)
  4. useStates(...states)
  5. withAsyncStates(states, fallbackOrOptions)
  6. updateStates(stateMap, data)
  7. AsyncRender
  8. persistStates(stateMap, initialData, onChange)
  9. compose(...funcs)
  10. hoc(functor)
  11. memoize(func)
  12. configure(optionsOrCallback)

About

Incredible fast state manager for React

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published