Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

conduxion

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

conduxion

Consequential Redux Actions

  • 1.0.7
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
2
decreased by-33.33%
Maintainers
1
Weekly downloads
 
Created
Source

Conduxion

Consequential redux actions

A small API extracting the goodness of https://github.com/edumentab/talks-redux-patterns by @krawaller.

import {actionCreatorFactory} from 'conduxion'
import produce from 'immer'

import {AppActionMould} from '../../../state.types';

import {STATE_KEY} from '../authentication.state';
import {setAppError} from '../../ui';

type SetIsAuthenticatedPayload = {
    isAuthenticated: boolean
}

export type SetIsAuthenticatedAction = AppActionMould<'SET_IS_AUTHENTICATED', SetIsAuthenticatedPayload>

export const [setIsAuthenticated, isSetIsAuthenticated] = actionCreatorFactory<SetIsAuthenticatedAction>({
     type: 'SET_IS_AUTHENTICATED',
     reducer(state, payload) {
         const {isAuthenticated} = payload;
    
         return produce(state, draft => {
             draft[STATE_KEY].isAuthenticated = isAuthenticated;
         })
     },
     consequence({action, dispatch}) {
         const {isAuthenticated} = action.payload;
         
         if (!isAuthenticated) {
             dispatch(setAppError('Not authenticated'));
             return;
         }
     }
});

Table of Contents

Philosophy

An alternative approach to redux where we put actions first, and view state as a consequence of them.

Instead of creating singleton reducers responsible for a single state slice, we create reducers for each individual action that can act across the entire state.

Should an action have consequences, they are declared on the action itself (as an event-emitter).

Installation

$ npm i -S conduxion

Please note that redux is a peer-dependency.

Usage

Creating a store

Using pre-fab factories.

import {Store} from 'redux';
import {makeStore, RootReducer, ConduxionAction} from 'conduxion';

type AppState = {
    // whatever you want
    [key: string]: any
}
type AppDependencies = {}
type AppAction = ConduxionAction<AppState, AppDependencies>
const INITIAL_APP_STATE: AppState = {}

const rootReducer: RootReducer<AppState, AppAction, AppDependencies> = (state = INITIAL_APP_STATE, action) => action.reducer
    ? action.reducer(state, action.payload)
    : state;

const store: Store<AppState, AppAction> = makeStore<AppState, AppAction, AppDependencies>(
    rootReducer,
    INITIAL_APP_STATE
);

export default store;

For your convenience, we also expose a dev version that automatically connects to Redux DevTools

import {Store} from 'redux';
import {createActionLogMiddleware, makeDevStore, RootReducer, ConduxionAction} from 'conduxion';

type AppState = {
    // whatever you want
    [key: string]: any
}
type AppDependencies = {}
type AppAction = ConduxionAction<AppState, AppDependencies>

const INITIAL_APP_STATE: AppState = {}

const rootReducer: RootReducer<AppState, AppAction, AppDependencies> = (state = INITIAL_APP_STATE, action) => action.reducer
    ? action.reducer(state, action.payload)
    : state;

const actionLog: any[] = [];

const store: Store<AppState, AppAction> = makeDevStore<AppState, AppAction, AppDependencies>(
    rootReducer,
    INITIAL_APP_STATE,
    {
        // createActionLogMiddleware mutates actionLog with each action fired
        additionalMiddleware: [createActionLogMiddleware(actionLog)]
    }
);

export default store;

Creating an action

Using the actionCreatorFactory() factory function.

import {actionCreatorFactory, ConduxionActionMould} from 'conduxion'

import {AppState, AppDependencies} from '../somewhere'
import {setAppError} from '../somewhere-else'

type AppActionMould<T extends string, P> = ConduxionActionMould<
    T,
    P,
    AppState,
    AppDependencies
>

type SetIsAuthenticatedPayload = {
    isAuthenticated: boolean
}

export type SetIsAuthenticatedAction = AppActionMould<'SET_IS_AUTHENTICATED', SetIsAuthenticatedPayload>

export const [setIsAuthenticated, isSetIsAuthenticated] = actionCreatorFactory<SetIsAuthenticatedAction>({
    type: 'SET_IS_AUTHENTICATED',
    // optional
    reducer(state, payload) {
        const {isAuthenticated} = payload;

        return {
            ...state,
            isAuthenticated
        }
    },
    // optional
    consequence({action, dispatch}) {
         const {isAuthenticated} = action.payload;
         
         if (!isAuthenticated) {
             dispatch(setAppError('Not authenticated'));
             return;
         }
    }
});

API

makeStore

Creates a conduxion redux store with consequence middleware applied.

import {Store} from 'redux'
import {ConduxionAction, RootReducer, MakeStoreOptions} from 'conduxion';

export function makeStore<State extends object, A extends ConduxionAction<State, Dependencies>, Dependencies extends object>(
    rootReducer: RootReducer<State, A, Dependencies>,
    initialState: State,
    opts: MakeStoreOptions<State, Dependencies> = {}
): Store<State, A>;

makeDevStore

Creates a conduxion redux store with consequence middleware as well as Redux DevTools middleware applied.

import {Store} from 'redux'
import {ConduxionAction, RootReducer, MakeStoreOptions} from 'conduxion';

export function makeStore<State extends object, A extends ConduxionAction<State, Dependencies>, Dependencies extends object>(
    rootReducer: RootReducer<State, A, Dependencies>,
    initialState: State,
    opts: MakeStoreOptions<State, Dependencies> = {}
): Store<State, A>;

actionCreatorFactory

Factory function returning an ActionCreator and ActionGuard for a gived redux action.

import {
    Action,
    ActionType,
    ActionReducer,
    ActionState,
    ActionPayload,
    Consequence,
    ActionDeps,
    ConduxionAction,
    ActionCreator,
    ActionGuard
} from 'conduxion'

type CreatorBlueprint<A extends Action<string, any, any, any>> = {
    type: ActionType<A>
    reducer: ActionReducer<ActionState<A>, ActionPayload<A>>
    isError?: boolean
    consequence?: Consequence<ActionState<A>, ActionDeps<A>, ActionPayload<A>>
}

export default function actionCreatorFactory<A extends ConduxionAction<any, any>>(
    blueprint: CreatorBlueprint<A>
): [ActionCreator<A>, ActionGuard<A>]

Types

There are a lot of types exposed by conduxion, here are a few of them. Please see the root types as well as the core types for a comprehensive list.

RootReducer

Redux root reducer for conduxion.

import {ConduxionAction} from 'conduxion'

export type RootReducer<
    State extends object,
    A extends ConduxionAction<State, Dependencies>,
    Dependencies extends object
> = (state: State | undefined, action: A) => State;

Action

The base interface for all conduxion actions. Enables use of consequence methods.

import {ActionReducer, Consequence} from 'conduxion';

export interface Action<
    Type extends string,
    Payload extends any,
    State extends object,
    Dependencies extends object> {
    type: Type
    error?: boolean
    sender?: string
    reducer?: ActionReducer<State, Payload>
    payload: Payload
    consequence?: Consequence<State, Dependencies, Payload> | Consequence<State, Dependencies, Payload>[]
}

Consequence

An action consequence method.

import {ConsequenceAPI} from 'conduxion'

export type Consequence<State extends object, Dependencies extends object, Payload extends any = any> = ((
    api: ConsequenceAPI<State, Dependencies, Payload>
) => void) & {
    name: string,
    displayName?: string
}

ConduxionActionMould

Generic representation of a conduxion action.

import {Action} from 'conduxion';

export type ConduxionActionMould<
    Type extends string,
    Payload,
    State extends object,
    Dependencies extends object
> = Action<Type, Payload, State, Dependencies>

MakeStoreOptions

Additional configuration for makeStore and makeDevStore.

import {Middleware} from 'redux';
import {ConsequenceGetter, Consequence} from 'conduxion';

export type MakeStoreOptions<State extends object, Dependencies extends object> = {
    additionalMiddleware?: Middleware[]
    dependencies?: Dependencies
    consequenceGetter?: ConsequenceGetter<State, Dependencies>
    initConsequence?: Consequence<State, Dependencies>
}

Keywords

FAQs

Package last updated on 17 Oct 2019

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc