React data

There are only few ways a pure React component can receive data:

  • props
  • state
  • context

All versions of FLUX use a combination of the above to achieve data flow and react to changes over time.

As you move away from props and towards state and context you increase component complexity.

Props

const Collapsible = (props) => {
  const { isOpen, toggle, children } = props;
  const classes = classnames({
    'collapsible': true,
    'collapsible-open': isOpen,
    'collapsible-closed': !isOpen
  });
  return (
    <div className={classes} onClick={toggle}>
      {children}
    </div>
  );
}

State

class CollapsibleStateful extends React.Component {
  static defaultProps = { isInitiallyOpen: true };
  constructor(props) {
    super(props);
    this.state = {
      isOpen: props.isInitiallyOpen,
    };
  }
  render() {
    const { isOpen } = this.state;
    const { children } = this.props;
    return (
      <Collapsible isOpen={isOpen} toggle={::this.toggle}>
        {children}
      </Collapsible>
    );
  }
  toggle() {
    this.setState({
      isOpen: !this.state.isOpen,
    })
  }
}

Context

Note: keep collapsible dumb and add the context to the parent.

const { shape, object } = React.PropTypes;
class Collapsible extends React.Component {
  static contextTypes = {
    css: shape({
      collapsible: shape({
        open: object,
        closed: object,
      })
    })
  };
  static defaultProps = { isInitiallyOpen: true };
  constructor(props, context) {
    super(props, context);
    this.state = {
      isOpen: props.isInitiallyOpen,
    };
  }
  render() {
    const { isOpen } = this.state;
    const { children } = this.props;
    const { open, closed } = this.context.css.collapsible;
    const styles = isOpen ? open : closed;
    return (
      <div styles={styles} onClick={::this.toggle}>
        {children}
      </div>
    );
  }
  toggle() {
    this.setState({
      isOpen: !this.state.isOpen,
    })
  }
}