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

v0.2.0

Published

Predictable state management solution for React applications.

Downloads

2

Readme

react-epics

Predictable state management solution for React applications. React-Epics is a valuable tool for organizing your state. Inspired by Redux it uses the power of RxJS observables and react hooks to manage state changes.

MIT Typescript Pull Requests GitHub last commit npm version

🚀 Epics

An Epic is a function which takes an stream of actions (action$), an stream of the current state (state$), and function returns an Observable of the new state.

Once you're inside your Epic, use any Observable patterns you desire as long as any output from the final, returned stream, is the new state.

This idea, which is based on redux allows us to use all RxJS awesome abilities in our React components with a powerful API.

🛠 Installation

react-epics needs both react and rxjs as peer dependencies.

npm

npm install react-epics rxjs react

yarn

yarn add react-epics rxjs react

🔧 Usage

1. Create your state types: src/types.ts

export type ICounter = {
  value: number;
};

2. Setup your epic: src/epics/counter.ts

import { map } from 'rxjs/operators';
import { merge } from 'rxjs';
import { Epic } from 'react-epics';
import { ICounter } from '../types';

export const initialState: ICounter = {
  value: 0,
};

export const epic: Epic<ICounter> = ({ ofType }) => {
  // plus action
  const plus$ = ofType('counter/plus').pipe(
    map(([action, state]) => {
      return { value: state.value + action.payload };
    }),
  );
  // minus action
  const minus$ = ofType('counter/minus').pipe(
    map(([action, state]) => {
      return { value: state.value - action.payload };
    }),
  );
  // merge all actions into one observable
  return merge(plus$, minus$);
};

3. Register your epics in the store: src/App.tsx

import * as React from 'react';
import { createStore, StoreProvider } from 'react-epics';
// epics
import * as counter from './epics/counter';
// components
import Counter from './components/Counter';

// store
const store = createStore({
  counter,
});

const App: React.FC = () => {
  return (
    <StoreProvider store={store}>
      <div className="App">
        <Counter />
      </div>
    </StoreProvider>
  );
};

4. Use it on any component: src/components/Counter.tsx

import * as React from 'react';
import { useDispatch, useEpic } from 'react-epics';
import { ICounter } from '../types.ts';

const Counter: React.FC = () => {
  const dispatch = useDispatch();
  const { value } = useEpic<ICounter>('counter'); // name of the registered epic

  // actions
  const plus = () =>
    dispatch({
      type: 'counter/plus',
      payload: 1,
    });
  const minus = () =>
    dispatch({
      type: 'counter/minus',
      payload: 1,
    });

  return (
    <div className="counter-wrapper">
      <h2>Couter: {value}</h2>
      <button onClick={plus}>+</button>
      <button onClick={minus}>-</button>
    </div>
  );
};

📖 Documentation - Deprecated!!!

useEpic()

This is a React hook that allows us to use RxJS Observables for state management.

type State = {...}
type Payload = {...}

type Dispatch = (action: Action<Payload>) => void;

type useEpic = (
  epic: Epic<Payload, State, Dependencies>,
  initialState: State,
  dependecies?: Dependencies,
) => [State, Dispatch, Error | null]

The useEpic() hook, accepts an epic function, the initial state and an optional dependency object. It returns an array with the current state, dispatch callback and a nullable error.

epic()

An Epic is a function which takes an stream of actions (action$), an stream of the current state (state$), and an optional object of dependencies, this function returns an Observable of the new state.

The idea of the Epic comes from redux-observable, but because redux-observable is redux middleware, the observable returned from the Epic emits new actions, react-epics expects the Epic to return an observable of state updates.

type State = {...}
type Payload = {...}

type Action = {
  type: string;
  payload: Payload;
};

type Action$<P> = Observable<Action>;

type State$ = Observable<State>;

type Epic<Payload, State, Dependencies = {}> = (
  actions$: Action$<Payload>,
  state: State$,
  dependecies: Dependencies,
) => State$;

Operators

ofType

This operator filters the actions emited by the actions obserbable (action$) depeding if the emited action type match with the action type parameter.

  type ofType(actionType: string) => OperatorFunction<Action<Payload>>
example:
type State = 'foo' | 'bar';
type Payload = {...}
const FooBarEpic: Epic<Payload, State> = (action$) => {

  const foo$ = action$.pipe(
    ofType('FOO'),
    mapTo('foo')
  );

  const bar$ = action$.pipe(
    ofType('BAR'),
    mapTo('bar')
  );

  return merge(foo$, bar$);
}

mapAction

The mapAction operator maps the emited value if the action match the action type parameter, notice that it doesn't apply a filter so the next actions emited won't be filtered out of the stream.

  type mapCallback(action: Action<Payload>) => State
  type mapAction(actionType: string, mapCallback) => OperatorFunction<State>
example:
type State = 'foo' | 'bar';
type Payload = {...}
const FooBarEpic: Epic<Payload, State> = (action$) => {
  return action$.pipe(
    mapAction(
      'FOO', (action) => 'foo'
    ),
    mapAction(
      'BAR', (action) => 'bar'
    ),
  );
}