Search code examples
javascriptreactjsflux

Working with Radio Buttons on Flux


Just started my first app in React and I want to know if there is a React way to work with Radio Buttons, I have a form with 4 radio buttons, I need to take 2 of the options selected and send that info to a backend.

class RadioBtns extends Component {

  constructor (props) {
    super(props);
    this.state = {
      greet : '',
      hello : '',
    };
  }

  render () {
    return (
      <div>
        <div>
          <form>
            <input type="radio" value="first" name="greet" onChange={this._onChangeGreet}/> Option 1
            <input type="radio" value="second" name="greet" onChange={this._onChangeGreet}/> Option 2
            <input type="radio" value="three" name="hello" onChange={this._onChangeHello}/> Option 3
            <input type="radio" value="four" name="hello" onChange={this._onChangeHello}/> Option 4
          </form>
          <hr />
          <button type="submit" onClick={this._submitSettings}>YES!</button>
        </div>
      </div>
    );
  }

  _onChangeGreet = ({ target }) => {
      this.setState({
        greet : target.value,
      });
  }

  _onChangeHello = ({ target }) => {
      this.setState({
        hello : target.value,
      });
  }

  _submitSettings = () => {
    console.log('submit');
  }

}

export default RadioBtns;

how do I send this states with the values to the stores ?

and here I have the action

@createActions(flux)
class RadioBtnsActions {

  constructor () {
    this.generateActions('optionSelected');
  }
}

export default RadioBtnsActions;

and in the Store

import flux from 'flux';
import RadioBtnsActions from 'actions/RadioBtnsActions';

@createStore(flux)
class RadioBtnsStore {
  constructor () {
    this.state = {
      radioSelected : false,
    };
  }

  @bind(RadioBtnsActions.optionSelected)
  optionSelected (option) {
    this.setState({
      radioSelected : option,
    });
  }
}

export default RadioBtnsStore;

Solution

  • Here's what we did in our project (simplified, use your imagination):

    First you create a RadioButton component that renders the actual input:

    render(){
      <div>
         <input id={this.props.id} type="radio"
           name={this.props.name} value={this.props.value}
           checked={this.props.checked} onChange={this.onChange}/>
         <label htmlFor={this.props.id}>{this.props.label}</label>
     </div>
    },
    
    onChange: function(ev){
        this.props.onChange(ev.target.checked, this.props.value);
    }
    

    Then you use that to implement a RadioButtonGroup component:

    render: function(){
        var name = this.name, value = this.props.value, onChange = this.onSingleRadioChange;
        var options = _.map(this.props.options, function(option){
            var id = name + '-' + option.value;
            return <RadioButton key={option.value} id={id} name={name} value={option.value} label={option.label} checked={option.value == value} onChange={onChange} />
        });
    
        return  <div>{options}</div>
    },
    
    onSingleRadioChange: function(checked, value){
        if(checked)
            this.props.onChange(value);
    }
    

    You can use it like this:

    <RadioButtonGroup name='greet' options={[{value: 'first', label: 'First'}, {value: 'second', label: 'Second'}]} onChange={val => { Actions.radioGroupChanged('greet', val);}}  />
    

    Where Actions.radioGroupChanged is the action that your store is listening on.

    Don't forget to use labels for better UX.

    Edit: here's a rough draft of the store, although we use Reflux, so it's a different API that what you have:

    var store = Reflux.createStore({
        radioGroups: {greet: 'first', hello: 'three'}, //state of the radio button groups lives here
    
        init(){
          this.listenTo(Actions.radioGroupChanged, this.onRadioGroupChanged);
        },
    
        onRadioGroupChanged(group, value){
          this.radioGroups[group] = value;
          this.trigger(); //this notifies the component that the store changed;
        }
    });
    

    The component then listens to the store and updates its own state:

    componentDidMount(){
      this.listenTo(store, () => { this.setState({radios: store.groups}) });
    }
    
    render(){
       return <RadioButtonGroup name='greet' value={this.state.radios.greet} .../>
    }