How to Creat a Dynamic <select> Menu with React

React is still new to me, along with everything that is software development. Therefore, it takes a bit more mental computation to understand exactly what I’m trying to accomplish.

In this case, I needed to understand how to get previously-stored values into a element in a form. The idea is that the user is utilizing this form to record meditation sessions — or what I refer to as mindful moments — and in this form the user records the location where they had that mindful moment. Chances are they’re going to meditate in the same location more than once, so we need to make it so that the user can either use an already-existing location, or create a new one.

Code Walk-through

Let’s see how to do this…

// LocationSelect component
import React from 'react';
import { connect } from 'react-redux';
import { getMoments } from '../actions/moments';

Of course, we need to import React and connect, and also the action to get our list of moments — a call to our API — which contains the location that we need for our later on.

Let’s initialize our component’s state:

class LocationSelect extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      location: ''
    };
  }

So we’re telling our component to store a location key in its state, but not yet giving it a value. We just giving that value a place to go later on.

Let’s get our moments object from our API:

  componentDidMount(){
    if (this.props.authToken){
     getMoments(this.props.authToken);
    }
  }

If our props contains the authToken , then run the getMoments action with that authToken. We want this to happen once this component mounts.

Inside our render(), we want to sort our select menu’s options to make it more user-friendly. To do this, we need to first get all of our previously-entered data, store it in a new array, then sort that array.

render() {
  let momentsList = [];
**  this**.props.moments.forEach(({ *id*, *location* }) => momentsList.push({ id, location }));
  let uniqueSet = [...new Set(momentsList.map(*moment* => moment.location))];

So we create our new array, momentsList. Since they’re passed as props, we need to grab them from there, and run a forEach, grabbing the id and the location from *each *iteration (in this case, each moment). Then, we’re pushing id and location into our new array from each moment we iterate over. We only want the id and location, not any other information that might be stored in that object.

We then need to create a new Set, so that we can store data of any type. We’re saying, Create a new array called uniqueSet, which will be a new Set created from a map() over our previous array, grabbing the location.

*I know this is rather messy — I’d love to know of a more succinct way to do this if possible!

Next, let’s sort that new array alphabetically:

let sortedList = uniqueSet
  .sort((*a*, *b*) => {
    *if* (a < b) *return* *-1*;
    *else* *if* (a > b) *return* *1*;
    *return* *0*;
  })
  .map((*location*, *index*) => <option key={index}>{location}</option>);

Here, we’re just sorting alphabetically. this is a rather common process. Basically, if parameter a is less than parameter b, return -1, but if a is greater than b, return 1, otherwise return 0.

As I understand it, this is looking at each bit and determining whether it is greater or less than the bit next to it, and sorting it according to our specifications. The least value letter is a, while the greatest value is z.

Our map function is taking the location and index of each of those now-sorted items and putting them into an for our to use later. Notice we’re using the index as our key for React, and location as our text to display.

Inside our return statement is where we’re going to see all of this come to fruition on the user-side.

return (
      <div className="dropdown">
        <label htmlFor="location">Location</label>
        <input
          required
          className="form-input"
          type="text"
          name="location"
          placeholder="create or choose"
          value={this.props.location}
          onChange={event => this.handleTextFieldChange(event, 'location')}
          maxLength="20"
          autoComplete="off"
        />
        <select onChange={event => this.handleTextFieldChange(event, 'location')}>
          {sortedList}
        </select>
      </div>
    );

Here you can see that we are rendering to the page an and our . Our input is the text field used to create a new location, while our select is where we’re rendering all previously-enter location items.

Our select is receiving our sortedList array to be used as s — remember when we wrote that above?

If we scroll up in our imaginative document here, we need to write our onChange handler, handleTextFieldChange.

handleTextFieldChange(event) {
    let location = event.target.value;
    let text = location // capitalize first letter
      .toLowerCase()
      .split(' ')
      .map(s => s.charAt(0).toUpperCase() + s.substr(1))
      .join(' ');
    this.props.setLocation(text, 'location');
  }

event.target.value is either our input or our select. If we type into our input field, or if we select an option from the menu. We’re also manipulating all text that gets put into that input field; we’re capitalizing the first character. This helps to keep things looking tidy. Users might feel like capitalizing one day, or using all lowercase the next. This way, our stored data is uniform.

Then we finish off our component:

const mapStateToProps = state => ({
  moments: state.moments.moments,
  authToken: state.auth.authToken
});
export default connect(mapStateToProps)(LocationSelect);

and render it in our parent component after importing it.

I understand this is a rough how-to. As one with not a ton of experience with React and JavaScript, and having no one in-person to bounce ideas off of, I was left with reading docs and seeing what others have done. I never did find something doing this same thing, so I had to utilize what I could piece together. For instance, Set is very new to me, and I honestly don’t think I used it in the correct manner. That said, it’s what worked for what I needed.

I do hope this has helped someone, and I very much welcome any and all input. Below, you can find the component in its entirety:

import React from 'react';
import { connect } from 'react-redux';
import { getMoments } from '../actions/moments';

class LocationSelect extends React.Component {
constructor(props) {
super(props);
this.state = {
location: ‘’
};
}

componentDidMount() {
if (this.props.authToken) {
getMoments(this.props.authToken);
}
}

handleTextFieldChange(event) {
let location = event.target.value;
let text = location // capitalize first letter
.toLowerCase()
.split(’ ‘)
.map(s => s.charAt(0).toUpperCase() + s.substr(1))
.join(’ ');
this.props.setLocation(text, ‘location’);
}

render() {
let momentsList = [];
this.props.moments.forEach(({ id, location }) => momentsList.push({ id, location }));
let uniqueSet = […new Set(momentsList.map(moment => moment.location))];

// sort list alpha, map to render
let sortedList = uniqueSet
.sort((a, b) => {
if (a < b) return -1;
else if (a > b) return 1;
return 0;
})
.map((location, index) => <option key={index}>{location}</option>);

// store locations to state
return (
<div className=“dropdown”>
<label htmlFor=“location”>Location</label>
<input
required
className=“form-input”
type=“text”
name=“location”
placeholder=“create or choose”
value={this.props.location}
onChange={event => this.handleTextFieldChange(event, ‘location’)}
maxLength=“20”
autoComplete=“off”
/>
<select onChange={event => this.handleTextFieldChange(event, ‘location’)}>
{sortedList}
</select>
</div>
);
}
}

const mapStateToProps = state => ({
moments: state.moments.moments,
authToken: state.auth.authToken
});


export default connect(mapStateToProps)(LocationSelect);


Thanks for reading. If you liked this post, share it with all of your programming buddies!

Further reading

How to Build First React Website

Learn about Video Navigation in React

☞ React - The Complete Guide (incl Hooks, React Router, Redux)

☞ Modern React with Redux [2019 Update]

☞ Best 50 React Interview Questions for Frontend Developers in 2019

☞ Learn React - Full Course for Beginners - React Tutorial 2019

☞ React (without Redux) - JWT Authentication Tutorial & Example

☞ React vs Angular vs Vue.js by Example

☞ MERN Stack Tutorial - Build a MERN App From Scratch ❤


This post was originally published here

#reactjs #react-native #javascript #web-development

How to Creat a Dynamic <select> Menu with React
1 Likes28.80 GEEK