Home

Awesome

Build StatusGreenkeeper Badge

react-stampit

A specialized stampit factory for React.

Create React components in a way analogous to React.createClass, but powered by a subset of the stampit API.

This library has been replaced by react-stamp.

Install

react-stampit can be installed via npm

npm install react-stampit

or by downloading the latest release.

What is this

This library is the result of wondering about what other ways a React component could be represented. Stamps are a cool concept, and more importantly have proven to be a great alternative to React.createClass and the ES2015 class due to their flexibility and use of multiple kinds of prototypal inheritance.

react-stampit has an API similar to React.createClass. The factory accepts two parameters, the React library and a description object.

stampit(React, {
  init: [],
  state: {},
  statics: {},

  // convenience props for React statics
  contextTypes: {},
  childContextTypes: {}.
  propTypes: {},
  defaultProps: {},

  // ...methods
});

The best part about stamps is their composability. What this means is that n number of stamps can be combined into a new stamp which inherits each passed stamp's behavior. This is perfect for React, since class is being pushed as the new norm and does not provide an idiomatic way to use mixins. (classical inheritance :disappointed:). While stamp composability on the surface is not idiomatic, the conventions used underneath are; it is these conventions that provide a limitless way to extend any React component.

mixin1.jsx

export default {
  componentWillMount() {
    this.state.mixin1 = true;
  },
};

mixin2.jsx

export default {
  componentWillMount() {
    this.state.mixin2 = true;
  },
};

component.jsx

import stampit from 'react-stampit';
import * as cache from 'react-stampit/utils/cache';

const id = cache.uniqueId();

export default React => {
  return cache.find(id) || cache.save(
    stampit(React, {
      state: {
        comp: false,
        mixin1: false,
        mixin2: false,
      },

      _onClick() {
        return this.state;
      },

      componentWillMount() {
        this.state.comp = true;
      },

      render() {
        return <input type='button' onClick={() => this._onClick()} />;
      },
    }), id
  );
};

app.jsx

import React from 'react';

import componentFactory from './component';
import mixin1 from './mixin1';
import mixin2 from './mixin2';

const Component = componentFactory(React).compose(mixin1, mixin2);

/**
 * Do things
 */
shallowRenderer.render(<Component />);
const button = shallowRenderer.getRenderOutput();

assert.deepEqual(
  button.props.onClick(), { comp: true, mixin1: true, mixin2: true },
  'should return component state with all truthy props'
);
  >> ok

You may have noticed several interesting behaviors.

This design pattern is optional, but recommended. Component factories are react-stampit's solution for avoiding the often hard to debug problems created by multiple instances of React. Read more about that here. By injecting the React library, we are able to guarantee the version and instance of React that a component will receive.

This goes hand in hand with designing components as factories. Node.js's internal caching will not work as expected for component factories, react-stampit's cache utility can be used as a replacement.

Event handlers require explicit binding. No magic. This can be done using .bind or through lexical binding with ES2015 arrow functions as shown in the example.

React methods are wrapped during composition, providing functional inheritance. Sweet.

This is shorthand syntax for:

stampit(null, {
  // stuff
});

If you feel limited by class, or want a fresh take on React.createClass, maybe give react-stampit a try and learn more about what stampit is all about. And please report any issues you encounter!

Docs

Examples

Pending Issues

License

MIT