node package manager
Loosely couple your services. Use Orgs to version and reuse your code. Create a free org »

relogic

Relogic

An abstraction to encapsulate flows of logic in React applications.
There is a demo and an API with full documentation.

Install

npm install --save-dev relogic

What is it ?

A simple way to organize the logic in React applications.

The idea is fairly simple: everything not enclosed in the lifecycle of a component can be either enclosed in the lifecycle of a parent component or is completely unrelated to any view.

relogic gives you a way to separate the code unrelated to the views and put it into an object passed to all the components.

You simply import

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { createMemory, Relogic, withLogic } from 'relogic';

prepare all your small pieces of logic

import history from 'path/to/history/library';
 
const resources: {
    authentication: { url: '/authentication} 
};
 
const api = {
    fetchCreate: (resource, params) => fetch(resource.url, params)
};
 
const localStorageLogic = localStorage => {
    rememberToken: token => localStorage.setItem('token', JSON.stringify(token))
};
 
const historyLogic = history => {
    return Object.assign({}, history, {
        redirectToEntry: () => history.push('/entryPage')
    });
}

combine them in a unique object, the application logic

const userLogic = ({ resources, api, localStorage, history }) => {
 
    async login(name, password) {
 
        const { token } = await api.fetchCreate(
            resources.authentication,
            { name, password }
        );
 
        localStorage.rememberToken(token);
 
        history.redirectToEntry();
    }
};
 
const logic = {
    user: userLogic({ 
        resources, 
        api, 
        localStorage: window.localStorage, 
        history 
    })
};

and inject the logic into all your components via a memory object.

const memory = createMemory();
memory.setLogic(logic);
 
ReactDOM.render(
    <Relogic memory="memory">
        <App />
    </Relogic>,
    document.getElementById('root')
);

And then, you can use it wherever you want

// somewhere down the hierarchy
 
class Login extends React.Component {
 
    /* all the lifecycle */
 
    render() {
        const { login, /* other properties like name and password */ } = this.state;
        return (
            <form className="Login"
                  onSubmit={(e) => {
                               e.preventDefault(); 
                               login(name, password);    
                           }}>
 
                { /* your inputs... */ }
            </form>
        );      
    }
};
 
export default withLogic(
    ({ getLogic }, props) => {
        return {
            login: getLogic().user.login;
        };
    }
)(Login);

OK, but what do I get with that ?

Well, you have just created a flow of logic.

It takes some dependencies as input which implies you can test them really easily and separately, you don't need to stub anything, and you can do integration tests more quickly.

Your whole application is now just a function which takes some dependencies as input, performs some computations, perhaps asynchronously, and renders views with their own lifecycle.
Basically, bootstrapping the application becomes a controlled process.

And now, since you create flows and inject them, you can also replace them...
Have a look at the demo to see how you can time travel in an application with both Redux and React Router.