0

I've been applying a Flux-like architecture to my React app, and am wondering if the app state is really meant to be kept in the store(s) rather than components. It seems like there are some scenarios where it might be good to have some components maintain their own state.

For instance, the below self-aware FormElement. I couldn't imagine writing that with a Flux-like architecture, where everything is dispatched to the store as an action. How would the store possibly keep track of all the different form elements, and their parent form?

In short: is it acceptable to have some components keep track of their own state, while most others use dispatch?

FormElement = React.createClass({
  displayName: 'FormElement',

  validations: {
    email: /^[A-Za-z0-9-._+]+@[A-Za-z0-9-]+[.A-Za-z0-9-]*\.[A-Za-z]{2,}$/,
    password: /.{6,}/
  },

  propTypes: {
    id: React.PropTypes.string.isRequired,
    label: React.PropTypes.string.isRequired,
    type: React.PropTypes.string,
    required: React.PropTypes.bool
  },

  getDefaultProps() {
    return {
      type: 'text',
      required: false,
      disabled: false
    }
  },

  getInitialState() {
    return {
      focused: false,
      filled: false,
      valid: true,
      invalidMessage: ''
    }
  },

  handleFocus(focusing) {
    let valid = true, errMsg = '';
    let inputVal = React.findDOMNode(this.refs.inputField).value;

    this.setState({focused: focusing});

    if (!focusing) {
      // Do some validations on blur
      if (this.props.required && !this.state.filled) {
        valid = false;
        errMsg = this.props.label + ' is required';
      }

      if (this.props.type === 'email' &&
        this.state.filled && !this.validFormat(inputVal, 'email')) {
        valid = false;
        errMsg = 'Invalid email address';
      } else if (this.props.type === 'password' &&
        this.state.filled && !this.validFormat(inputVal, 'password')) {
        valid = false;
        errMsg = 'Password too short';
      }
    }

    this.setState({valid, invalidMessage: errMsg}, function () {
      // Notify parent that something changed
      //this.props.onAction(this);
    });
  },

  handleChange({target}) {
    this.setState({
      value: target.value,
      filled: target.value.length > 0
    });
  },

  validFormat(str, type) {
    return !!str.match(this.validations[type]);
  },

  render() {
    let formElement;
    const labelClasses = classNames({
      'focused': this.state.focused || this.state.filled
    });
    const groupClasses = classNames({
      'form-group': true,
      'has-error': !this.state.valid
    });

    if (_.contains(['text', 'email', 'password'], this.props.type)) {
      formElement = (
        <div className={groupClasses}>
          <label
            className={labelClasses}
            htmlFor={this.props.id}>
            {this.state.invalidMessage ?
              this.state.invalidMessage : this.props.label}
          </label>

          <input type={this.props.type}
                 className="form-control"
                 id={this.props.id}
                 ref="inputField"
                 onFocus={this.handleFocus.bind(null, true)}
                 onBlur={this.handleFocus.bind(null, false)}
                 onChange={this.handleChange}
                 disabled={this.props.disabled} />
        </div>
      );
    } else if (this.props.type === 'submit') {
      formElement = (
        <div>
          <button type="submit"
                  className="btn btn-primary"
                  disabled={this.props.disabled}>{this.props.label}
          </button>
        </div>
      );
    }

    return formElement;
  }
});
ffxsam
  • 26,428
  • 32
  • 94
  • 144

1 Answers1

0

The flux pattern is primarily used for handling data between the server and the components. I also use an app.store for handling state that effects more than one component and an api.store for handling actions that deal with the server api (requesting or saving data).

If the scope of the state is only regarding a single component then you can contain the state within the component.

J. Mark Stevens
  • 4,911
  • 2
  • 13
  • 18