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

react-redux-controllers

v1.0.0-12.2

Published

*IMPORTANT: The library is in **alpha** version and API might change drastically. Use with caution.*

Downloads

10

Readme

React/Redux Controllers

IMPORTANT: The library is in alpha version and API might change drastically. Use with caution.

NOTE: This document assumes the reader is familiar with Redux and React.

This microframework was created for organizing the code of React/Redux applications. It is important to understand that it does not introduce any new fundamental concepts to a regular React/Redux application internals. It provides the utilities for structuring React/Redux application in a way, that make them more readable and manageable. The main goal is to reduce the boilerplate code introduced by Redux.

This is achieved by three essential primitives:

  • Controller
  • Container
  • Application

And one small, but important utility class:

  • Action

NOTE: Actions in fact can be used in any Redux application separately from the rest of the framework. Action class itself has zero dependencies.

Installation

The library is available as a package on NPM:

npm install --save react-redux-controllers

Controller

As the name of the library implies, the central concept here is Controller. However, this is not a controller as in MVC (although, admittedly it does share certain similarities, hence the name). It is better to think of it as a "data controller", responsible for managing the certain part of the application state. "Managing" includes:

  • Sending relevant actions in response to certain related events
  • Modifying the state by providing the relevant reducer
  • Providing access and if necessary transforming the data in the managed part of the state

Here is a quick example with explanation to kick things off. Most application require certain kind of user authentication (e.g. email/password login). Our AuthenticationController will contain the logic.

import { Controller, Action } from "react-redux-controllers";

// Each controller is a class, that subclasses Controller
class AuthenticationController extends Controller {
  
  // These two parameters are required and handled by the library
  // You can pass your own parameters
  constructor(application, mountPath) {
    super(application, mountPath);
    
    // Create an action called "login" in the context of our controller
    this.createAction("login");
  }
  
  // This function can be used to initiate login from anywhere
  // (mostly from view-layer of course)
  login(email, password, dispatch) {
    const { login } = this.actions;
    
    dispatch(login.started());
    dispatch(() => {
      // do actual login with email and password...
      // ...and on sucess call
      dispatch(login.success(user));
    });
  }
  
  // Here we create reducer, using handy utility class Action
  reducer() {
    return Action.createReducer(
      login.onStarted((state) => Object.assign({}, state, {
        isLoggingIn: true
      }),
      
      login.onSuccess((state, user) => Object.assign({}, state, {
        isLoggingIn: false,
        user
      })
    );
  }
  
  // And finally here are accessors to the relevant information in state
  isLoggingIn(state) {
    // The state here is a global state. In order to access the part managed by the
    // controller we use this.$(), which is just a shortcut to this.rootState()
    return this.$(state).isLoggingIn;
  }
  
  // ...here we just return the data, but this is a good place to do any work
  // in order to transform data from implementation detailed storage structure
  // into some meaningful interface
  getUser(state) {
    return this.$(state).user;
  }
  
  // We need controllers to have names in order to reference them from elsewhere.
  // As most people minify their JavaScript code, it is unfortunately a neccessity
  // to specify the name explicitly VS extracting it from the class name :( 
  static get name() {
    return "Authentication";
  }
}

In this example we don't process errors, but I think you can already imagine how this can be done.

Container

Controllers encapsulate all the data processing logic, but it is up to Containers to connect it to the view layer. This is what you would use in place of connect() in traditional Redux application. And in fact Container() calls it internally. However, instead of requiring to write the boring mapToState and mapToDispatch stuff, we will just connect it to the Controller referenced by name.

import { Container } from "react-redux-controllers";

class Login extends Component {
  // ...
}

export default Container(Login, "Authentication");

Behind the scene this does some automatic props mapping. Specifically for the AuthenticationController we have created above the container will receive and propagate the following props:

  • login - mapped as a function, dispatch will be automatically passed as the last argument
  • isLoggingIn - mapped as the value, by calling isLoggingIn() function of the controller
  • user - mapped as the value, by calling getUser() function of the controller

They mapped using certain simple conventions. If the results do not satisfy you in certain specific cases, you can alter them in either Controller or Container. This of course will kill the magic, but sometimes it is necessary.

Application

The Application has two responsibilities:

  • Initializing the Redux store and launching the React application (this most likely will not be the case in final version though)
  • Acting as a repository for the Controllers

The base Application class from this package is React-agnostic (can be used with both DOM and Native). There are 2 supplementary packages, which provide ready-to-use Application subclasses:

Here is an initialization example:

import { Application } from "react-redux-controllers-dom";

// ...

const app = new Application();
app.register(AuthController);
app.run(document.getElementById('root'), <Login />);

You might want to subclass Application even further, if you follow OOP-style. For example, Application subclass would be a good place to initialize some kind of Web API client you will be using. It can be then exposed as a property. Each Controller can access its Application via the application property.