Skip to content

rkkautsar/redux-companion

master
Switch branches/tags
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Redux Companion

GitHub GitHub package version npm bundle size (minified + gzip) npm Travis Codecov FOSSA Status

Opinionated way to reduce boilerplate on async (or sync) logic, like fetching data etc. Zero dependency (Although it only makes sense to use together with Redux AND Redux Thunk).

Packages

Installation

npm i redux-companion

Why?

I find myself exhausted of writing (or copying) a lot of the same set of redux state, reducer, actions, and thunks for interacting with the api, so I thought why not make it easier?

Quick Start

See example usage.

Let's recreate Redux Todo List example with redux-companion and Ducks pattern.

Reducers

reducers/todos.js
import { createAction, createReducer } from 'redux-companion';

export const addTodo = createAction('ADD_TODO');
export const toggleTodo = createAction('TOGGLE_TODO');

const handlers = {
  [addTodo]: (state, payload) => [
    ...state,
    {
      id: payload.id,
      text: payload.text,
      completed: false
    }
  ],
  [toggleTodo]: (state, payload) =>
    state.map(todo => (todo.id === payload ? { ...todo, completed: !todo.completed } : todo))
};
const todo = createReducer(handlers, []);
export default todo;
reducers/visibilityFilter.js
import { createAction, createReducer } from 'redux-companion';

export const setVisibilityFilter = createAction('SET_VISIBILITY_FILTER');

export const VisibilityFilters = {
  SHOW_ALL: 'SHOW_ALL',
  SHOW_COMPLETED: 'SHOW_COMPLETED',
  SHOW_ACTIVE: 'SHOW_ACTIVE'
};

const handlers = {
  [setVisilibityFilter]: (state, payload) => payload
};
const visibilityFilter = createReducer(handlers, []);
export default visibilityFilter;

Not too much different, eh? But for me it's slightly better and less boilerplate. How about async actions?

Let's actually save our todo list to the server.

services/api.js
import axios from 'axios';
export const putTodos = todos => axios.put(`${BASE_URL}/todos/`, todos).then(res => res.data);
reducers/todos.js
import {
  createAction,
  createReducer,
+  createAsyncMiddleware,
+  createAsyncStatusReducer
} from 'redux-companion';
import { putTodos } from '../services/api';

export const addTodo = createAction('ADD_TODO');
export const toggleTodo = createAction('TOGGLE_TODO');

const handlers = {
  [addTodo]: (state, payload) => [
    ...state,
    {
      id: payload.id,
      text: payload.text,
      completed: false
    }
  ],
  [toggleTodo]: (state, payload) =>
    state.map(todo => (todo.id === payload ? { ...todo, completed: !todo.completed } : todo))
};

+ export const todosMiddleware = createAsyncMiddleware({
+   [saveTodos]: async ({ dispatch, getState }) => {
+     const todos = getState().todos;
+     try {
+       await putTodos(todos);
+       // do something after save action complete
+     } catch (e) {
+       // handle error here
+     }
+   }
+ });

+ export const { actions: saveTodos, reducer: saveTodosStatusReducer } = createAsyncStatusReducer(
+   'SAVE_TODOS'
+ );

const todo = createReducer(handlers, []);
export default todo;

And that's it, when you dispatch the saveTodos() action, the middleware (that you have to register, see example) will catch the action and run the associated api call with the todos.

License

FOSSA Status

About

Opinionated way to reduce boilerplate on async (or sync) redux logic, like fetching data etc. Zero dependency.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •