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

repatch

v1.3.12

Published

Dispatch reducers

Downloads

673

Readme

npm version npm downloads corp-check status

Dispatch reducers

Repatch is just a simplified Redux, that let you create actions more briefly by dispatching reducers directly.

store.dispatch(state => ({ ...state, counter: state.counter + 1 }));

In this terminology, an action is a function that returns a reducer:

const increment = amount => state => ({
  ...state,
  counter: state.counter + amount
});

store.dispatch(increment(42));

Motivation

Redux has verbose action management. The most of redux projects do not need sctrict action administration. Action types, action creators and the reducer's action handlers are mutually assigned to each other. Repatch's purpose is creating actions briefly.

The simplest way to keep the immutable action controlled dataflow and define actions briefly is dispatching pure functions (as reducers) to the store.

Comparison with Redux

Repatch is

  • less verbose
  • smaller (the minified version is less than 1 KB)
  • faster

than Redux.

Working with Redux

If you have to keep the official Redux in your project, then you can use the redux-repatch or redux-repatch-creator enhancers.

API Reference

Examples

Articles

Repatch - the simplified Redux

Installation

npm install --save repatch

How to use

ES6

import Store from 'repatch';

const store = new Store(initialState);

CommonJS

const Store = require('repatch').Store;

UMD

<script src="https://unpkg.com/repatch/dist/repatch.js"></script>

or the minified bundle:

<script src="https://unpkg.com/repatch/dist/repatch.min.js"></script>

and

const Store = Repatch.Store;
const thunk = Repatch.thunk;

Compatibility with react-redux

Repatch's interface is very similar to Redux, therefore you can use with react-redux.

const unsubscribe = store.subscribe(() => console.log(store.getState()));

store.dispatch(resolveFetchingUsers(users));

unsubscribe();

TODO app in brief

const store = new Store([]);

const addTodo = text => todos => [...todos, { text, checked: false }];

const checkTodo = index => todos => todos.map(
  (todo, i) => (i === index ? { ...todo, checked: !todo.checked } : todo)
);

const editTodo = (index, text) => todos => todos.map(
  (todo, i) => (i === index ? { ...todo, text } : todo)
);

const removeTodo = index => todos => todos.filter((_, i) => i !== index);

Sub-reducers

We do not need to reduce always the whole state of the store. Repatch also offers a way to combine sub-reducers, those describe a deeply nested property in the state. We just define a helper function that takes a nested reducer as argument, and returns a reducer that reduces the whole state:

const reduceFoo = fooReducer => state => ({
  ...state,
  bar: {
    ...state.bar,
    foo: fooReducer(state.bar.foo)
  }
});

Using that we can define easily an action, that sets an x property in the foo object:

const setX = x => reduceFoo(state => ({ ...state, x }));

Middlewares

A repatch middleware takes the store instance, a next function and the previous reducer. The middleware can provide a new reducer via the next function.

Middleware: Store -> Next -> Reducer -> any

Use the addMiddleware method to chaining middlewares:

const store = new Store(initialState)
  .addMiddleware(mw1)
  .addMiddleware(mw2, mw3);

Middleware example

This simple logger middleware logs the current- and the next state:

const logger = store => next => reducer => {
  const state = store.getState()
  const nextState = reducer(state)
  console.log(state, nextState)
  return next(_ => nextState)
}

const store = new Store(initialState).addMiddleware(logger)

Async actions

The thunk middleware is useful for handling async actions similar to redux-thunk.

import Store, { thunk } from 'repatch';

const store = new Store(initialState).addMiddleware(thunk);

In thunk async actions reducer returns a function (delegate):

const updateUser = delta => state => async (dispatch, getState) => {
  try {
    const editedUserId = getState().editedUser;
    dispatch(toggleSpinner(true));
    await api.updateUser(editedUserId, delta);
    await dispatch(fetchUsers());
  } catch (error) {
    dispatch(state => ({ ...state, error: error.message }))
  } finally {
    dispatch(toggleSpinner(false));
  }
};

It is possible to embed async actions within each other too and awaiting their resolving:

await dispatch(fetchUsers());

Injecting extra argument

It is possible to inject extra arguments into async actions:

import Store, { thunk } from 'repatch';
import api from './api';
import { hashHistory } from 'react-router';

const store = new Store(initialState)
  .addMiddleware(thunk.withExtraArgument({ api, hashHistory }));

Then you can access these arguments in your delegates:

const updateUser = delta => state =>
  async (dispatch, getState, { api, hashHistory }) => {
    // ...
  }

This way you can keep your async actions independently from outer instances or side-effects. This practice is useful for testing.

Testing

Sync actions

Testing a reducer is easy:

import * as assert from 'assert';
import { changeName } from './actions';

// ...

it('changeName', () => {
  const state = { name: 'john' };
  const nextState = changeName('jack')(state);
  assert.strictEqual(nextState.name, 'jack');
});

Async actions

For async action tests you need to instantiate the Store and provide mocked extra arguments.

import Store, { thunk } from 'repatch';
import * as assert from 'assert';
import { fetchUsers } from './actions';

const mockUsers = [{ username: 'john' }];
const mockApi = {
  getUsers: () => Promise.resolve(mockUsers)
}

// ...

it('fetchUsers', async () => {
  const state = { users: [] };
  const store = new Store(state)
    .addMiddleware(thunk.withExtraArgument({ api: mockApi }));
  await store.dispatch(fetchUsers());
  const nextState = store.getState();
  assert.deepEqual(nextState.users, mockUsers);
});

License

MIT

Community

https://twitter.com/repatchjs

Developed by

JayStack