0.6.1 • Published 3 years ago

react-mono-state v0.6.1

Weekly downloads
-
License
ISC
Repository
github
Last release
3 years ago

react-mono-state

State Management Lib - reactive and less boilerplate. No need external middleware to perform state change asynchronously and you can handle any actions on any components and also make effects on it by using hooks - useActionHandler, useStoreEffect. Remaining useful hooks are - useSelector, useDispatch, useStore etc.

counter | todo

counterState

import { RegisterState } from "react-mono-state";

export const counterState: RegisterState<Counter> = {
  stateName: "counter",
  initialState: { loading: false, count: 0 },
  mapActionToState(emit) {
    return {
      inc(state) {
        emit({ loading: false, count: state.count + 1 });
      },
      dec(state) {
        emit({ loading: false, count: state.count - 1 });
      },
      async asyncInc(state) {
        emit({ loading: true, count: state.count });
        await delay(1000);
        emit((c_state) => ({ loading: false, count: c_state.count + 1 }));
      },
    };
  },
};

function delay(ms: number) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

counterComponent

import { useSelector, useDispatch } from "react-mono-state";

export default () => {
  const dispatch = useDispatch();
  const { count, loading } = useSelector((state: AppState) => state.counter);
  return (
    <div>
      <button onClick={(e) => dispatch("inc")}>+</button>
      <button onClick={(e) => dispatch("asyncInc")}>Async(+)</button>
      <button onClick={(e) => dispatch("dec")}>-</button>
      <span>{loading ? "loading..." : count}</span>
    </div>
  );
};

app.ts

import React from "react";
import { Provider, createStore } from "react-mono-state";
import { counterState } from "../states/counterState";

import "../styles/globals.css";

export const store = createStore([counterState]);

function MyApp({ Component, pageProps }) {
  return (
    <Provider store={store}>
      <Component {...pageProps} />
    </Provider>
  );
}

export default MyApp;

Action Handler and Effects search Demo

We are going to develop a search component. This component has a SearchInput child component which dispatches search-input action every times user strokes in the keyboard. The search-input action catches by the useStoreEffect hook which debounces a while so that he can collect some more keys and then send a request to the server to pull the search result and finally dispatches a new action (named search-result) with pulled data.

At the moment search-result action dispatchs - Search component is ready to handle this action by the useActionHandler hook and then finally render the search results.

All these are happening without reducer and middleware. awesome!

Reactive programming is COOL - What a nice combination. its really useful and effective.

SearchInput component

import React from "react";
import { useStoreEffect, useDispatch } from "react-mono-state";
import {
  debounceTime,
  distinctUntilChanged,
  map,
  switchMap,
  filter,
} from "rxjs/operators";
import { from } from "rxjs";

export default () => {
  const dispatch = useDispatch();

  useStoreEffect((action$) =>
    action$.whereType("search-input").pipe(
      debounceTime(320),
      distinctUntilChanged(),
      filter(({ payload }) => !!payload),
      switchMap((action) => getData(action.payload)),
      map((res) => ({ type: "search-result", payload: res }))
    )
  );

  return (
    <div>
      <input
        onChange={(e) =>
          dispatch({ type: "search-input", payload: e.target.value })
        }
        placeholder="search wiki..."
      />
    </div>
  );
};

function getData(text) {
  return from(
    fetch(
      `https://en.wikipedia.org/w/api.php?&origin=*&action=opensearch&search=${text}&limit=5`
    )
      .then((d) => d.json())
      .then((d) => d)
  );
}

Search component

import React from "react";
import SearchInput from "./SearchInput";
import { useActionHandler } from "react-mono-state";
import { map } from "rxjs/operators";

export default () => {
  const [{ loading, data }] = useActionHandler((action$) =>
    action$.whereType("search-result").pipe(map((action) => action.payload))
  );

  const res = loading ? (
    <div>No search result</div>
  ) : (
    data[1].map((text, index) => <div key={index}>{text}</div>)
  );

  return (
    <div>
      <SearchInput />
      {res}
    </div>
  );
};
0.6.1

3 years ago

0.6.0

3 years ago

0.3.0

3 years ago

0.2.1

3 years ago

0.2.0

3 years ago

0.5.0

3 years ago

0.2.3

3 years ago

0.4.0

3 years ago

0.3.1

3 years ago

0.2.2

3 years ago

0.2.5

3 years ago

0.2.4

3 years ago

0.1.5

3 years ago

0.1.4

3 years ago

0.1.3

3 years ago

0.1.2

3 years ago

0.1.1

3 years ago

0.1.0

3 years ago