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

repertoire

v0.1.6

Published

Repertoire is a tool that adds fluidity to react+redux apps.

Downloads

13

Readme

repertoire.js

Build Status NPM version codecov


Homepage | Using Repertoire | API Reference

What's Repertoire

A small utility library which aims at simplifying building React + Redux apps.

It works by simply adding the well-known Controller concept to a web application built with React as the view layer and removing the need of all the boiler plate code for actions, reducers, middlewares etc.

Installation

Repertoire works together with React and Redux, so the following packages are needed as pre-requisites (peer dependencies) in your application:

  • react
  • redux
  • react-redux

You can install Repertoire from NPM, using:

$ npm install repertoire --save

Anatomy of a Repertoire App

Building an app with React & Redux has become much simpler. The example below is a basic user administration module, starting with the main component. We're also using the React Router to handle our application's routing needs.

├── modules/admin/
|     ├── components/
|     |      ├── UserAdd.js
|     |      ├── UsersList.js
|     |      └── SelectedUser.js
|     ├── api.js
|     ├── controller.js
|     └── index.js
└── index.js

1. index.js

This is the place where the Redux store is created and the app is being initialized.

import React from 'react'
import ReactDOM from 'react-dom'
import {Provider} from 'react-redux'
import {
  BrowserRouter as Router,
  Route
} from 'react-router-dom';
import {StoreManager} from 'repertoire'

import Admin from './modules/admin/index.js'
import Dashboard from './modules/dashboard/index.js'

const routes = [
  {
    path: '/',
    exact: true,
    controller: Dashboard
  },
  {
    exact: true,
    path: '/admin',
    controller: Admin
  }
];

// creating the main Redux store
const storeManager = new StoreManager(routes);

// rendering the main component
ReactDOM.render(<Provider store={storeManager.getStore()}>
  <Router>
    {routes.map((route, index) => {
      return <Route key={index} 
                    path={route.path} 
                    exact={route.exact} 
                    component={controller.component}/>
    })}
  </Router>    
</Provider>, document.getElementById('react-view'));

2. The Admin Controller

The Controller is the main thing that Repertoire adds to your application's architecture. It does that by combining the individual redux pieces, such as reducers, actions and middlewares, together in one logical entity.

Each public method on the controller that will be exposed on the instance will be a redux action, and each of them will have an implicit reducer associated by default.

Every action needs to return a Promise and the result of the promise will be added to the store. If an action returns a value synchronously, that value will be converted to a Promise automatically.

The controller is also the place where the Redux state properties are defined, which are passed to React as props. Use the this.state setter and getter to define the props to be passed to React or to inspect the current value of the Redux store.

import {BaseController} from 'repertoire'
import AdminApi from './api.js'

export default class AdminController extends BaseController {
  // the section of the redux store which this controller will operate on
  get stateNamespace() {
    return 'admin';
  }
  
  /**
   *
   * Methods that start with "__" are not processed as actions
   *
   * @param currentUser
   * @private
   */
  __handleFetchUsers(currentUser) {}
  
  setSelectedUser (selectedUser) {
    return {
      selectedUser
    };
  }
  
  fetchAllUsers () {
    return AdminApi.getUsers().then(result => ({users: result}));
  }
  
  addNewUser (params) {
    let addUserSuccess = false;
    let lastThrownError = null;

    return AdminApi.addNewUser(params)
      .then(_ => {
        addUserSuccess = true;

        return AdminApi.getUsers();
      })
      .catch(error => {
        lastThrownError = error;

        // return the existing list of users if an error occurred
        return this.state.users;
      })
      .then(users => ({
        addUserSuccess,
        lastThrownError,
        users
      }));
  }
  
  constructor(component) {
    super(component);
    
    this.state = {
      /**
       * Each function defined on this setter will received the namespaced 
       *  redux store value
       */
      users(store) {
        return store.users || [];
      },
      
      selectedUser(store) {
        return store.selectedUser || '';
      },
      
      addUserSuccess(store) {
        return store.addUserSuccess || false;
      }
    };
    
    // Final step. This is calling the connect() utility from react-redux
    this.connect();
  }
}

The api.js file contains a bunch of methods which will fire HTTP requests to the backend and return a Promise. Anything that returns a Promise will work.

3. The Admin React Component

In the main React component file we will have to instantiate the controller, passing the component itself, and export that instance. Other than that it's standard react / redux stuff.

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Controller from './controller.js';
import UserList from './components/UsersList.js';
import UserAdd from './components/UserAdd.js';
import SelectedUser from './components/SelectedUser.js';

class Admin extends Component {
  static propTypes = {
    users: PropTypes.array.isRequired,
    fetchUsers: PropTypes.func.isRequired
  };

  constructor(props) {
    super(props);

    this.state = {
      // ...
    };
  }

  componentWillMount() {
    this.props.fetchUsers();
  }

  onUserCreateCancel(e) { /* ... */ }

  onCreateUserSubmit(params) {  
    this.props.addNewUser(params);
  }

  handleUserClick(e) {
    const user = e.target.id;
    if (user) {
      this.props.setSelectedUser(user);
    }
  }

  render() {
    const {showUserCreateForm, addUserSuccess} = this.state;
    const {users, selectedUser, lastThrownError} = this.props;
    
    return users.length > 0 ? <div>
      <UserAdd showForm={showUserCreateForm}
               onCancelAddUser={this.onUserCreateCancel.bind(this)}
               onCreateUserSubmit={this.onCreateUserSubmit.bind(this)} />
                       
      <UserList users={filteredUsers || users}
                onClick={this.handleUserClick.bind(this)}
                selectedUser={selectedUser}/>

      {
        selectedUser ? <SelectedUser users={users}
                                     selectedUser={selectedUser} /> : null
      }
    </div> : null;
  }
}

export default new Controller(Admin);

That's pretty much it - a very basic Repertoire example, not necessarily functional though. You'll need an html template and a web server of course, along with a webpack (or other package manager) build system, but we're not going to focus on that part here.