redux-tools

Redux Tools to make redux easy

Redux Tools

Redux Tools to make redux easy and reduce boilerplate with useful tools and conventions.

Contents

Getting Started

Please view the example folder to get a quick introduction or continue reading.

Models

The Problem

Does this folder structure look familiar to you?

src/
    actions/
        index.js
        products.js
        user.js
    components/
        App.js
        Header.js
        Product.js
    reducers/
        index.js
        products.js
        user.js
    selectors/
        index.js
        products.js
        user.js
    types/
        index.js
        products.js
        user.js
    index.js
    store.js

This is the basic organization shown in many different redux tutorials and examples. This works great until, one day, it doesn't. It becomes cumbersome to make changes across multiple folders when you're only really updating one thing. This is where models come in.

The Solution

The solution is to place things together by domain rather than type. All fetching, updating, and calculating for a domain lives inside one model. This includes actions, types, reducers, selectors, sagas. So that example app structure using models would look like this:

src/
    components/
        App.js
        Header.js
        Product.js
    models/
        products/
            actions.js
            index.js
            reducer.js
            sagas.js
            selectors.js
        user/
            actions.js
            index.js
            reducer.js
            sagas.js
            selectors.js
        index.js
    index.js
    store.js

Model Conventions

A model can be a folder with separate files for actions, reducer, selectors, etc. Or for simple models just a single file may be all you need (similar to Ducksin many ways). At the end of the day it will be an object with one or several of the following keys (each piece is optional):

  • actions
    • an object where each key is an action creator function
  • reducer
    • a reducer function for a branch of the state object, usually with the same name as the model itself
  • sagas
    • a single saga function that will be forked by the root reducer
  • selectors
    • an object of selector functions related to the model
  • types
    • an object of SNAKE_CASEkeys and namespace/SNAKE_CASEvalues for use in reducers and sagas (and anywhere else you need them)

Next let's look at each piece in a little more detail.

Actions and Types

This is what a typical definition for a type and action looks like:

const SET_FIRST_NAME = 'user/SET_FIRST_NAME';
const setFirstName = (payload) => ({
    payload,
    type: SET_FIRST_NAME,
});

And that gets even more repetitive when you start dealing with asynchronous actions:

const SAVE_REQUEST = 'user/SAVE_REQUEST';
const SAVE_SUCCESS = 'user/SAVE_SUCCESS';
const SAVE_FAILURE = 'user/SAVE_FAILURE';
const saveRequest = (payload) => ({
    payload,
    type: SAVE_REQUEST,
});
const saveSuccess = (payload) => ({
    payload,
    type: SAVE_SUCCESS,
});
const saveFailure = (payload) => ({
    payload,
    type: SAVE_FAILURE,
});

That repetition was a source of great angst for us so we thought there's a great opportunity for convention and tooling to reduce boilerplate.

The first step was to decide that since actions and types are so closely related anyway, why don't we explicitly couple them together?

Conventions for Actions and Types
  • actions have a typeand a payload. Action creators will always accept a single parameter that will be placed onto the payloadkey of the action object.
  • types will be SNAKE_CASEwith a namespaceof any case
  • action creators will have the camelCaseversion of the type's SNAKE_CASEvalue.
  • action creators will be generated automatically from types

So using our conventions and adding in redux-toolstooling, we can greatly reduce the boilerplate for creating actions and types. Here's an equivalent of the above two examples:

import { Async, Basic } from 'redux-tools/types';
import { generateActionsAndTypes } from 'redux-tools';

const { actions, types } = generateActionsAndTypes('user', [
    new Async('SAVE'),
    new Basic('SET_FIRST_NAME'),
    new Basic('SET_LAST_NAME'),
]);

Reducers

Model reducers are combined into the root reducer using Redux's combineReducersfunction.

Sagas

Model sagas are combined by forking each saga inside the root saga.

API Reference

Types

Use an implementation of the Typeclass when defining your types. Redux Tools comes with two types defined out of the box: Asyncand Basic.

Basic

When used with generateActionsAndTypes, this will result in a namespaced type and action creator.

import { Basic } from 'redux-tools/types';
import { generateActionsAndTypes } from 'redux-tools';

const { actions, types } = generateActionsAndTypes('user', [new Basic('SET_FIRST_NAME')]);

console.log(actions);
// { setFirstName: (payload) => ({ payload, type: 'user/SET_FIRST_NAME' }) }

console.log(types);
// { SET_FIRST_NAME: 'user/SET_FIRST_NAME' }

Async

When used with generateActionsAndTypes, this will result in request, success, and failure action creators and types.

import { Async } from 'redux-tools/types';
import { generateActionsAndTypes } from 'redux-tools';

const { actions, types } = generateActionsAndTypes('user', [new Async('SAVE')]);

console.log(actions);
/*
{
    saveRequest: (payload) => ({ payload, type: 'user/SAVE_REQUEST' }),
    saveSuccess: (payload) => ({ payload, type: 'user/SAVE_SUCCESS' }),
    saveFailure: (payload) => ({ payload, type: 'user/SAVE_FAILURE' }),
}
*/

console.log(types);
/*
types: {
    SAVE_REQUEST: 'user/SAVE_REQUEST',
    SAVE_SUCCESS: 'user/SAVE_SUCCESS',
    SAVE_FAILURE: 'user/SAVE_FAILURE',
}
*/

generateActionsAndTypes

Arguments

  1. namespace(string)
  2. types(array)

Returns

{
    actions: {},
    types: {},
}

Example

import { Async, Basic } from 'redux-tools/types';
import { generateActionsAndTypes } from 'redux-tools';

const { actions, types } = generateActionsAndTypes('user', [
    new Async('SAVE'),
    new Basic('SET_FIRST_NAME'),
    new Basic('SET_LAST_NAME'),
]);

console.log(actions);
/*
{
    saveRequest: (payload) => ({ payload, type: 'user/SAVE_REQUEST' }),
    saveSuccess: (payload) => ({ payload, type: 'user/SAVE_SUCCESS' }),
    saveFailure: (payload) => ({ payload, type: 'user/SAVE_FAILURE' }),
    setFirstName: (payload) => ({ payload, type: 'user/SET_FIRST_NAME' }),
    setLastName: (payload) => ({ payload, type: 'user/SET_LAST_NAME' }),
}
*/

console.log(types);
/*
types: {
    SAVE_REQUEST: 'user/SAVE_REQUEST',
    SAVE_SUCCESS: 'user/SAVE_SUCCESS',
    SAVE_FAILURE: 'user/SAVE_FAILURE',
    SET_FIRST_NAME: 'user/SET_FIRST_NAME',
    SET_LAST_NAME: 'user/SET_LAST_NAME',
}
*/

models.create

Function to combine your different models for use in your app. Typically used in the index.jsfile in your models directory.

Arguments

  1. models(object)

Returns

{
    actions,
    reducer,
    sagas,
    selectors,
    types,
}

Example

import app from './app';
import lists from './lists';
import { models } from 'redux-tools';
import todos from './todos';

export const { actions, reducer, sagas, selectors, types } = models.create({
    app,
    lists,
    todos,
});

console.log(actions);
/*
{
    app: { ... },
    lists: { ... },
    todos: { ... },
}
*/

// Root reducer function to use in your redux store
console.log(reducer);

// Root saga generator function to pass to the saga middleware
console.log(sagas);

console.log(selectors);
/*
{
    app: { ... },
    lists: { ... },
    todos: { ... },
}
*/

console.log(types);
/*
{
    app: { ... },
    lists: { ... },
    todos: { ... },
}
*/

TODO

withErrorReporting: extend to allow raygun / crashalitics / error reporting system withRetry: extend to allow raygun / crashalitics / error reporting system

HomePage

https://github.com/Prefinem/redux-tools

Repository

https+https://github.com/Prefinem/redux-tools


上一篇:sass-flex-mixin
下一篇:aqueduct-flood

相关推荐

  • (转载)如何通俗易懂的理解Redux

    作者:Wang Namelos 链接:https://www.zhihu.com/questio...(https://www.zhihu.com/question/41312576/answer/9...

    2 年前
  • 面试还问redux?那我从头手撸源码吧(中间件篇)

    昨天的文章手写了一版redux的核心源码(https://segmentfault.com/a/1190000016799698),redux库除了数据的状态管理还有一块重要的内容那就是中间件,今天我...

    2 年前
  • 阅读redux源码_compose

    先上源码: 重点看一句就够了: 现在我们先假设一个数组,有3个函数,分别是x,y,z 那么发生什么了,接下来就一步一步解释 1. 变成reduce模式: 2. reduce第一次执行,...

    2 年前
  • 跟着例子一步步学习redux+react-redux

    前言 本文不会拿redux、reactredux等一些react的名词去讲解,然后把各自用法举例说明,这样其实对一些react新手或者不太熟悉redux模式的开发人员不够友好,他们并不知道这样使用...

    2 年前
  • 超级易懂的redux-saga原理解析

    原文地址(https://github.com/zyl1314/blog/issues/14) 前言 笔者最近在做一些后台项目,使用的是Ant Design Pro(https://github...

    2 年前
  • 读redux源码总结

    redux介绍 redux给我们暴露了这几个方法 我们来依次介绍下 createStore 源码 个人觉得compose(a,b,c)(d)后的代码就是a(b(c(d))),co...

    2 年前
  • 详解redux异步操作示例

    一、redux基础 (https://img.javascriptcn.com/3c838d74abd0220ea77efc3756edb0cd) redux 通过 dispatch(a...

    2 年前
  • 详解react、redux、react-redux之间的关系

    本文介绍了react、redux、reactredux之间的关系,分享给大家,也给自己留个笔记,具体如下: React 一些小型项目,只使用 React 完全够用了,数据管理使用props、sta...

    2 年前
  • 记录一篇redux-saga的基本使用过程

    安装 配置action actionType 创建文件,在文件中添加需要的action类型 createActions 创建文件,在文件中编写action 配置red...

    2 年前
  • 记录一下react脚手架+redux+antd v4 实现登录鉴权,多级路由的学习过程

    前两天学习了下React,特记录下学习过程,react新手有哪里可以优化的往大佬留言指点,小弟万分感谢! 项目初始化 1、react脚手架 删除多于文件src留下App.js以及index....

    1 个月前

官方社区

扫码加入 JavaScript 社区