Search code examples
javascriptreactjsreact-props

Adding a radio button value to parent component in react


The parent component store all the state.

The function myChangeHandler trigger on any onChange and change the state

myChangeHandler(event) { this.setState({ [event.target.name]: event.target.value });

and on changing the value of radio button should return in the "Guide is" line Here is the code and let me know if i miss anything

// Get a hook function
const {useState} = React;

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      username: '',
      avail:'available',
      $avail:'non-available',
      brandGuideline:'',
    };
    this.myChangeHandler = this.myChangeHandler.bind(this);
  }

  myChangeHandler(event) {
    this.setState({
      [event.target.name]: event.target.value
    });
  }render(){
    return(
      <div>
        <Child username = {this.state.username}
          myChangeHandler = {this.myChangeHandler}
          />
      </div>
    )
  }
}

class Child extends React.Component {
  render() {
    return (
      <div className="label">
        <label>
          username
        </label>
        <input
          type='text'
          name='username'
          value={this.props.username}
          onChange={this.props.myChangeHandler}
          />
        <h1>My username: {this.props.username}</h1>
        <div>
          <label>
            We have a Brand Guide
          </label>
          <input 
            type='radio'
            name='brandGuideline'
            value={this.props.$avail}
            onChange={this.props.myChangeHandler}
            />Yes
          <input 
            type='radio'
            name='brandGuideline'
            value={this.props.avail}
            onChange={this.props.myChangeHandler}
            /> No
        </div>
        <h1>Guide is: {this.props.brandGuideline}</h1>
      </div>
    );
  }
};

ReactDOM.render(
  <Parent />,
  document.getElementById("react")
);
[event.target.name]: event.target.value
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>


Solution

  • Your issue related to missing props data from parent to child.

    Like writing:

    value = {this.state.i_am_not_exist_prop};

    1/2. First mistake

    Before

    {/* Parent Before */}
    <Child username = 
      {this.state.username}
      myChangeHandler = {this.myChangeHandler}
    />
    

    Send avail and $avail as props.

    Should be:

    {/* Parent After step 1*/}
    <Child 
     username = {this.state.username}
     myChangeHandler = {this.myChangeHandler}
     avail= {this.state.avail}
     $avail = {this.state.$avail}
    />
    

    2/2. Second mistake

    Parent component:

    myChangeHandler(event) {
      console.log([event.target.name]); /* brandGuideline */
      this.setState({
        [event.target.name]: event.target.value
      })
    };
    

    This [event.target.name] = "brandGuideline" (Use console.log). Again you need to send this as a prop to the child.

    Pass brandGuideline as a prop:

    {/* Parent After step 1 & 2 */}
    <Child 
      username = {this.state.username}
      myChangeHandler = {this.myChangeHandler}
      avail= {this.state.avail}
      $avail = {this.state.$avail}
      brandGuideline =  {this.state.brandGuideline}
    />
    

    1 + 2 Working snippet

    class Parent extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          username: '',
          avail:'available',
          $avail:'non-available',
          brandGuideline:'',
        };
        this.myChangeHandler = this.myChangeHandler.bind(this);
      }
    
      myChangeHandler(event) {
        this.setState({
          [event.target.name]: event.target.value
        });
      }render(){
        return(
          <div>
            <Child 
              username = {this.state.username}
              myChangeHandler = {this.myChangeHandler}
              avail= {this.state.avail}
              $avail = {this.state.$avail}
              brandGuideline =  {this.state.brandGuideline}
              />
          </div>
        )
      }
    }
    
    class Child extends React.Component {
      render() {
        return (
          <div className="label">
            <label>
              username
            </label>
            <input
              type='text'
              name='username'
              value={this.props.username}
              onChange={this.props.myChangeHandler}
              />
            <h1>My username: {this.props.username}</h1>
            <div>
              <label>
                We have a Brand Guide
              </label>
              <input 
                type='radio'
                name='brandGuideline'
                value={this.props.$avail}
                onChange={this.props.myChangeHandler}
                />Yes
              <input 
                type='radio'
                name='brandGuideline'
                value={this.props.avail}
                onChange={this.props.myChangeHandler}
                /> No 
            </div>
            <h1>Guide is: {this.props.brandGuideline}</h1>
          </div>
        );
      }
    };
    
    ReactDOM.render(
      <Parent />,
      document.getElementById("react")
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    <div id="react"></div>

    Child VS Parent Practices

    If myChangeHandler function related specifically to the child form and not reusable somehow (Like in your case) - it's better to put the function their instead of sending this function as prop from the parent.

    avail & $avail states could be unit to one boolean available: true/false (More semantic & usefull for Conditional Rendering & Easier to read).

    Start here: