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

rrrr

v0.1.5

Published

React Redux Router Wrapper for easily composing React components attached to react-router and react-redux, without repeated / confusing boilerplate

Downloads

4

Readme

React Redux Router w(R)apper

Installation

$ npm install --save rrrr

Technologies

https://github.com/facebook/react

https://github.com/reactjs/react-redux

https://github.com/ReactTraining/react-router

Motivation

Configuring and maintaining a react application with the two most popular libraries, react-redux and react-router, can be a huge pain. This package attempts to alleviate some of the headaches encountered while using the three technologies together, providing a consistent and user-friendly API.

Usage

A lot of the boilerplate required by react-redux has been removed, and a cleaner, more powerful out-of-the-box API has been provided. A lot of great work has gone in to making react-redux work under the hood, and we preserve that great work, but the boilerplate surrounding a react-redux system gets wildly out of control very fast. This package will also handle async actions by default.

Basic Example

// ./setup.js
import React from 'react';
import ReactDOM from 'react-dom';
import { create } from 'rrrr';
import defaultReduxState from './defaultReduxState'; // our default state of the application at load time
import Index from './Index'; // our entry point to the react application

ReactDOM.render(
  create(defaultReduxState, Index),
  document.getElementById('root'),
);
// ./Index.js
import React from 'react';
import { compose } from 'rrrr';

class Index extends React.Component {
  componentDidMount() {
    // if you want to see the full definition of the props object while developing
    console.log(this.props);
  }
  render() {
    return (
      <div>
        <h1>Hello {this.props.storeProps.message}!</h1>
        <button onClick={this.props.storeActions.syncAction}>Click me!</button>
        <button onClick={this.props.storeActions.asyncAction}>Click me!</button>
      </div>
    )
  }
}

// see the below url to understand how `props` and `actions` are used internally by the react-redux `connect` function
// https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options
const props = () => ({ message: 'world!' });
const actions = () => {
  asyncAction: {
    action: new Promise((resolve) => {
      setTimeout(resolve, 5000);
    }),
    end: () => ({ message: 'mars!' }),
    start: () => ({ message: 'loading content...' }),
  },
  syncAction: () => ({ message: 'moon!' }),
};

export default compose(Index, { actions, props });

Props

By default, all React components are built with a props object. These fields represent the data passed in to the component allowing you to display dynamic / re-usable content.

This namespace gets polluted when using third-party libraries and their higher-order components. This is an obvious and deliberate side-effect of these libraries, but it can also create some confusion should you want to use a prop name that is already in use by a parent HOC. This package attempts to alert you when you are using a reserved keyword, but it cannot be guaranteed. In order to provide the best user experience, all props passed in are now hoisted to their appropriate namespaces inside the props object, preserving the usual requirements in the mean time.

The props object, by default, will have the following definition:

| Field Name | Source | Purpose | |-------------|-------------|------------------------| | renderProps | developer | These are the props you can pass through to a composed Component to allow re-use of a react-redux connected component | | storeProps | react-redux | These are the props computed by react-redux, allowing you to use the global store for storage / manipulation | | storeActions | react-redux | Actions to manipulate the global react-redux store | | routerProps | react-router | match, location, history provided by react-router |

Actions

There are two types of actions, synchronous, and asynchronous.

Synchronous

A synchronous action will operate in real-time, and manipulate the react-redux instantaneously, which will then traverse your react component tree and update all the props necessary.

To define a syncronous function, simply pass in a function through the actions compose config paramater, and call it via props.storeActions.actionName.

// storeActions.sync('foo', 'bar', 'baz');

const actions = {
  sync: (foo, bar, baz) => ({ foo, bar, baz }),
};

compose(Component, { actions });

Asynchronous

An asynchronous action refers to the action you are performing, which in most cases is a network request, but it can be any operation. Usually, your UI will want to provide user feedback to alert them something is happening in the background.

Unlike defining a synchronous function as a function, you would define your asynchronous action as an object, with the action key.

// storeActions.asyncExample(foo, bar, baz);

const asyncExample = {
  action: (foo, bar, baz) => doSomethingAsynchronously(foo, bar, baz),
  end: ({ state, result, props }) => {
    return { loading: false, foo: 'bar', result: result.http_response };
  },
  start: ({ state }) => {
    return { loading: true, foo: 'baz' };
  },
  error: ({ result }) => ({ loading: false, error: 'something bad happened', result: result.http_status_code }),
};

compose(Component, { actions: { asyncExample } });

The start, end, and error functions do exactly what you may imagine. When the action starts, the start function is called, and redux store is updated with the function return value. When the action ends, the end function is called, and the redux store is updated with the function return value. error allows you to catch an error per action should something have gone wrong.

The action function is what you would call from within your React component; allowing you to pass through any arguments to relay to your asynchronous function.

Function signatures

Actions

For a sync function and async .action function, the signature of the call are the arguments the pass in to them when you call them:

// storeActions.sync('a', 'b', 'c');
// foo = 'a', bar = 'b', baz = 'c'
// props = { foo, bar, baz }, state = reduxState
sync = (foo, bar, baz, { props, state }) => ({ foo, bar, baz }); 

// storeActions.async('a', 'b', 'c');
// foo = 'a', bar = 'b', baz = 'c'
// notice here we cannot access the props or state object
async = {
  action: (foo, bar, baz) => ({ foo, bar, baz }),
};

start, end, error

async = {
  action: (foo, bar, baz) => ({ foo, bar, baz }),
  // state = redux state, props = { foo, bar, baz }
  start: ({ state, props }) => ({}),
  // result = the result of the async action
  end: ({ state, props, result }) => ({}),
  // result = the error thrown when processing the action
  error: ({ state, props, result }) => ({}),
};

API

create(Component[, { defaultReduxState = {}, historyProps = {} } = {}])

This function is what you should use to initialize your React application. It will take care of all the context bindings and other requirements for keeping your app sync'd to both react-router and react-redux.

Usage

import React from 'react';
import ReactDOM from 'react-dom';
import { create } from 'rrrr';
import ReactComponent from './ReactComponent';

ReactDOM.render(
  create(ReactComponent),
  document.getElementById('root'),
);

compose(Component[, config = { actions = {}, props = {} }])

Connect your Component to the react-redux and react-router data stores.

Usage

import React from 'react';
import { compose } from 'rrrr';

const ReactComponent = ({
  storeActions: {
    action,
  },
  storeProps: {
    message,
  },
}) => (
  <div onClick={action}>
    <h1>Hello {message}</h1>
  </div>
);

const props = state => state; // take the current store state and map all the fields to our component directly
const actions = { action: () => ({ message: 'world' })}; // update the store state 'message' field to 'world'

export default compose(ReactComponent, { actions, props });