Skip to content

Instantly share code, notes, and snippets.

@jviereck
Created June 4, 2015 13:00
Show Gist options
  • Save jviereck/7f63cb331d9becb057a7 to your computer and use it in GitHub Desktop.
Save jviereck/7f63cb331d9becb057a7 to your computer and use it in GitHub Desktop.

(As followup to this Tweet.)

Question: Given the following definition of the Counter class:

// BASED on example in Readme.md at
// https://github.com/gaearon/redux/blob/f8f512b229357c84bbef40099c52e011737f0373/README.md

import React, { PropTypes } from 'react';
import { increment, decrement } from './actions/CounterActions';
import { container } from 'redux';
import counterStore from './stores/counterStore';

@container({
  actions: { increment, decrement },
  stores: { counter: counterStore }
})
export default class Counter {
  static propTypes = {
    increment: PropTypes.func.isRequired,
    decrement: PropTypes.func.isRequired,
    counter: PropTypes.number.isRequired
  };
  
  render() {  
    ..
  }
}

it seems information passed to the @container function and the definition of the propTypes are redundant. That is given the definition in @container it should be possible to compute the static propTypes from within the function call to container.

While computing the propTypes for the actions is easy doable (they are alwasy just functions), it turns out to be problematic to do this for the stores as the expected PropType is not clear (in the above example, it is not obvious that counterStore yields a PropTypes.number). To work around this limitation, how about defining the PropTypes directly inline when specifing the stores on the @container?

@container({
  actions: { increment, decrement },

  // IDEA 1)
  // Define the store variables and their types directly inline here.
  stores: { counter: [counterStore, PropTypes.number.isRequired] }

  // IDEA 2)
  // Alternative idea: Use a function to wrap the `counterStore` with a type
  // annotation, where the `@container` can then interpret.
  stores: { counter: ReduxPropTypes.number.isRequied(counterStore) }
})
export default class Counter {
  // No need to specify the prop types here explicit anymore - they are computed
  // from the `@container` now.
  //
  // static propTypes = {
  //  increment: PropTypes.func.isRequired,
  //  decrement: PropTypes.func.isRequired,
  //  counter: PropTypes.number.isRequired
  // };
  
  render() {  
    ..
  }
}
@gaearon
Copy link

gaearon commented Jun 4, 2015

it seems information passed to the @container function and the definition of the propTypes are redundant. That is given the definition in @container it should be possible to compute the static propTypes from within the function call to container.

Yes, unless you make a mistake in @container definition. propTypes let you validate at the most important boundary: when data flows into the component. So if you made a mistake in @container definition, this will save you. If you're just getting started Redux, it's likely you'll misunderstand how @container works, so propTypes will help you here too.

If propTypes are generated, static analysis tools like ESLint won't see them. There is an ESLint rule for unused props, it's pretty cool.

Better to use built-in tools that something custom like ReduxPropTypes. This also lets you quickly remove the decorator and use <Container> component when/if you decide to do that, without suddenly needing to specify the propTypes.

Some repetition is good IMO, especially when it concerns types and JavaScript.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment