How to create an React component from select that in the bind event "change" picks the right value that was selected?

Asked

Viewed 2,088 times

1

Good night!

I am trying to make a select component that is used more than once within another Parent component.

To create the "option" tags, I map inside the array I created as a state of the Parent/App class.

So far, so good. However, when I select an option, he understands that I changed the state that was set to an array, as a single value that in this case would be the value I selected.

Follows code:

import React, { Component } from 'react';
import './App.css';

class App extends Component {

  constructor (props) {
    super(props)
    this.state = {
      value: '?',
      //list
      typeOfSearch: [
        {
          value: 'animated',
          name: 'animated'
        },
        {
          value: 'debuts',
          name: 'debuts'
        },
        {
          value: 'playoffs',
          name: 'playoffs'
        },
        {
          value: 'teams',
          name: 'teams'
        }
      ],
      //timeframe
      period: [
        {
          value: 'week',
          name: 'week'
        },
        {
          value: 'month',
          name: 'month'
        },
        {
          value: 'year',
          name: 'year'
        },
        {
          value: 'ever',
          name: 'ever'
        }
      ],
      //timeframe
      amountResults: [
        {
          value: '10',
          name: '10'
        },
        {
          value: '20',
          name: '20'
        },
        {
          value: '30',
          name: '30'
        },
      ],
    }
    this.handleChange = this.handleChange.bind(this);
  }



  handleChange(event) {

    const target = event.target;
    const value = target.value;
    const name = target.name;

    this.setState({
        [name]: value,
    });

    console.log(event.target.value);
  }

  render() {

    const createItem = (item, key) => <option key = {key} value = {item.value}>
     {item.name} </option>;

    return (
      <div className="container">

        <SelectFilter handleChange={this.handleChange} value={this.state.value} name="typeOfSearch">
            {this.state.typeOfSearch.map(createItem)}
          </SelectFilter>

          <SelectFilter handleChange={this.handleChange} value={this.state.value} name="period">
            {this.state.period.map(createItem)}
          </SelectFilter>

          <SelectFilter handleChange={this.handleChange} value={this.state.value} name="amountResults">
            {this.state.amountResults.map(createItem)}
          </SelectFilter>

      </div>
    );
  }
}

class SelectFilter extends Component {
  render(){

    return (<select onChange={this.props.handleChange} value={this.props.value} name= {this.props.name}>
              {this.props.children}
            </select>)
        }
}


export default App;

I really appreciate any help!

1 answer

1


You’re almost there, the problem is you’re about writing the array when you should set value. In practice the code you have creates this:

this.setState({
    typeOfSearch: 'debuts'
});

and that’s not what you want because typeOfSearch is an array.

Suggestion:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      values: {},
      //list
      typeOfSearch: [
        {
          value: "animated",
          name: "animated"
        },
        {
          value: "debuts",
          name: "debuts"
        },
        {
          value: "playoffs",
          name: "playoffs"
        },
        {
          value: "teams",
          name: "teams"
        }
      ],
      //timeframe
      period: [
        {
          value: "week",
          name: "week"
        },
        {
          value: "month",
          name: "month"
        },
        {
          value: "year",
          name: "year"
        },
        {
          value: "ever",
          name: "ever"
        }
      ],
      //timeframe
      amountResults: [
        {
          value: "10",
          name: "10"
        },
        {
          value: "20",
          name: "20"
        },
        {
          value: "30",
          name: "30"
        }
      ]
    };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(name, value) {
    this.setState(
      {
        values: {
          ...this.state.values,
          [name]: value
        }
      },
      () => console.log("Novos valores:", this.state.values)
    );
  }

  render() {
    const createItem = (item, key) =>
      <option key={key} value={item.value}>
        {item.name}
        {" "}
      </option>;

    const selects = ["typeOfSearch", "period", "amountResults"].map(name => {
      return (
        <SelectFilter
          handleChange={e => this.handleChange(name, e.target.value)}
          key={name}
          value={this.state.values[name]}
          name="typeOfSearch"
        >
          {this.state[name].map(createItem)}
        </SelectFilter>
      );
    });
    return <div className="container">{selects}</div>;
  }
}

class SelectFilter extends React.Component {
  render() {
    return (
      <select
        onChange={this.props.handleChange}
        value={this.props.value}
        name={this.props.name}
      >
        {this.props.children}
      </select>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("container"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>


<div id="container"></div>

  • Hello Sergio! You always the savior of the homeland. Thank you for your return. The problem is that this way, if I prompt the 3 selects, when selecting one, the other goes back to the first value, as if the same value that I pass to a select, was replicated to the 3. I wanted to change the select that was selected, without changing the value of the other 2.

  • In the method handleChange, I made a switch using the "name" property of each select. I created 3 empty States, one for each type of property, and 3 cases changing the value of each state: handleChange(event) { &#xA; switch (event.target.name) { &#xA; case "typeOfSearch": &#xA; this.setState({ &#xA; typeOfSearchSelected: event.target.value, &#xA; }); &#xA; break; I don’t think it looks very elegant, but it worked.

  • @Alinevianna had not noticed that you were having 1 state for 3 selects... this is not a good idea :) I added a suggestion with an example. Take a look :)

  • 1

    was great! I will debug the code calmly to understand better what you did. Thank you so much for your help once again. ;)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.