I have a useState called isPackage which is a boolean that starts as false. I use this hook in a simple JSX select, which when isPackage is true requires it to be enabled but when it is false it is disabled. The problem starts from the rendering since although usPackage is false, the select is shown enabled. This is my code:
UseState:
const [isPackage, setIsPackage] = useState(false)
JSX:
<select disabled = { isPackage ? true : false }>
I change the state of isPackage using this function:
const handlerPresentationSelected = () => {
setIsPackage(!isPackage)
}
If I make the first change using the function above, it is executed correctly to pass isPackage to true, when I use the function again it correctly changes to false, however the select is always enabled.
Per this answer, https://stackoverflow.com/a/8311341/12101554, you have to set disabled on the <option> tags, not the <select> tag.
const [isPackage, setIsPackage] = useState(false)
return (
<div className="App">
<button onClick={() => setIsPackage((cur) => !cur)}>toggle isPackage: {isPackage.toString()}</button>
<br />
<select>
<option disabled={isPackage}>a</option>
<option disabled={isPackage}>b</option>
</select>
</div>
);
If your options are in an array, then just set that property on the <select> in the .map
Based on the description of the question:
when isPackage is true requires it to be enabled but when it is false it is disabled
It would seem to indicate that perhaps this line should be the other way around:
<select disabled = { isPackage ? true : false }>
In addition, it seems that a required property should also be set when isPackage is true. With this added, the logic could be put in this way:
// If isPackage is true, the select is required, and not disabled
// If isPackage is false, the select is not required, and is disabled
<select {...{[isPackage ? "required" : "disabled"]: true}}>
And to toggle isPackage based on previous value on the button:
<button onClick={() => setIsPackage((prev) => !prev)}>
Here is a quick example to visualize the changes:
(It can run in the snippets for convenience)
const App = () => {
const [isPackage, setIsPackage] = React.useState(false);
return (
<div className="app">
<h3>{`isPackage is: ${isPackage}`}</h3>
<button onClick={() => setIsPackage((prev) => !prev)}>
Toggle isPackage 👆
</button>
<h3>
Toggle isPackage to set select <span>disabled</span> or{" "}
<span>required</span>
</h3>
<select
{...{
[isPackage ? "required" : "disabled"]: true,
}}
>
<option>Option 1</option>
<option>Option 2</option>
</select>
<span>* required</span>
</div>
);
};
ReactDOM.render(<App />, document.querySelector("#root"));
h3 > span:first-of-type {
color: grey;
}
h3 > span:last-of-type {
color: crimson;
}
select:disabled + span {
opacity: 0;
}
select:required + span {
opacity: 1;
color: crimson;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>
Hope this will help.
Your isPackage type is already a boolean so you can just pass it to the disabled property of select tag.
// Get a hook function
const {useState} = React;
const App = () => {
const [isPackage, setIsPackage] = useState(false);
const handlerPresentationSelected = () => {
setIsPackage(!isPackage);
};
return (
<div>
<button onClick={handlerPresentationSelected}>Click</button>
<select disabled={!isPackage}>
<option value="dog">Dog</option>
<option value="cat">Cat</option>
<option value="hamster">Hamster</option>
<option value="parrot">Parrot</option>
<option value="spider">Spider</option>
<option value="goldfish">Goldfish</option>
</select>
<h1>{String(isPackage)}</h1>
</div>
);
};
// Render it
ReactDOM.createRoot(
document.getElementById("root")
).render(
<App/>
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
Here I however tried to make the second div visible if a value is selected in the first dropdown. But I want to make a form where there will be 3 dropdown but only the first will be visible where the user will select any value and the 2nd dropdown will be accordingly. I even need to fetch the values using API. Here's an example of the form what I'm trying to make : https://donate.alauddintrust.com Thanking you!
import React from 'react';
import Section2 from '../Sections/Section2'
class App1 extends React.Component {
//set the statte default value
constructor(props) {
super(props);
this.state = {value: 'hide'};
}
// set the state value based on select option value
divstatus = (e) =>{
this.setState({value: e.target.value});
}
render() {
return (
<>
<div className="container">
<header class="page-header">
<h1 className={['text-warning']}>Donate <i>Now</i></h1>
</header>
<form className="donation-form form-horizontal container" id="donation-form">
<div id="donation-type-group" className="form-group">
<label htmlFor="recurrence">Donation Type <span className="required">*</span></label>
<select id="donation_type" onChange={this.divstatus} name="donation_type" className="form-control">
<option value="show">Select Donation Type</option>
<option value="hide">Sadaqa</option>
<option value="2">Fitrana</option>
<option value="3">Zakat</option>
<option value="4">Fidya</option>
<option value="5">Qurbani</option>
<option value="6">Donation</option>
<option value="15">Kaffara</option>
</select>
</div>
<div className={this.state.value}>
<div id="donation-type-group" className={['form-group']}>
<label htmlFor="recurrence">Programs<span className="required">*</span></label>
<select id="donation_type" name="donation_type" className="form-control">
<option value="">Select Donation Type</option>
<option value="1">Sadaqa</option>
<option value="2">Fitrana</option>
<option value="3">Zakat</option>
<option value="4">Fidya</option>
<option value="5">Qurbani</option>
<option value="6">Donation</option>
<option value="15">Kaffara</option>
</select>
</div>
</div>
<div class="text-center">
<button type="submit" class="btn btn-lg btn-primary">Submit donation</button>
</div>
</form>
<hr/>
<Section2 />
</div>
</>
)
};
}
export default App1;
I did somthing similar a while ago, you can display the first dropdown and onChange of the first dropdown trigger the API call to update the state to hold the options for the second dropdown, and in the second dropdown section when the api results are empty dont render the second dropdown (could use a (results) ?? <GoodComponent/> will only show if results not empty)
could also add a loading state value to disable the dropdowns in between API calls and listen to its changes using a useEffect hook
Why is the <select> I create in the constructor not updated when I pick another flavor in it? The other select, as well as the text, is updated.
class ConstructorComponent extends React.Component {
constructor() {
super();
this.state = {
icecream: 'vanilla',
};
this.select = (
<select
value={this.state.icecream}
onChange={this.onChange}
>
<option value="chocolate">Chocolate</option>
<option value="vanilla">Vanilla</option>
<option value="strawberry">Strawberry</option>
</select>
);
}
onChange = event => {
this.setState({
icecream: event.target.value,
});
};
render() {
return (
<div>
Icecream flavor: {this.state.icecream}
<br />
{this.select}
<br />
<select
value={this.state.icecream}
onChange={this.onChange}
>
<option value="chocolate">Chocolate</option>
<option value="vanilla">Vanilla</option>
<option value="strawberry">Strawberry</option>
</select>
</div>
);
}
}
ReactDOM.render(
<ConstructorComponent />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
I made it work by cloning this.select in render() like so: {React.cloneElement(this.select, {value: this.state.icecream})}
But making this.select a method instead, as suggested by several answers to my question is probably better. I'll see what works best with my actual code, and not just this dumbed down example :)
Because this.state.icecream in your first select is interpreted only once, when you define this.select in the constructor. So when your ConstructorComponent rerenders a second time when its state changes, there is nothing to update in your first select.
You need to define this.select as a function returning the <select>, like this:
this.select = () => {
return (
<select
value={this.state.icecream}
onChange={this.onChange}
>
<option value="chocolate">Chocolate</option>
<option value="vanilla">Vanilla</option>
<option value="strawberry">Strawberry</option>
</select>
)
}
And call this.select() in the render.
You can also create a reference to the <select> in the render by using the prop ref:
render() {
<select
value={this.state.icecream}
onChange={this.onChange}
ref={select => (this.select = select)} // the magic happens here
>
<option value="chocolate">Chocolate</option>
<option value="vanilla">Vanilla</option>
<option value="strawberry">Strawberry</option>
</select>
}
In doing so, you don't need to define this.select as a function in your constructor.
The first select doesn't work because it's only ever rendered once, in the constructor. The second select works because it's re-rendered every time the app state updates.
If it helps, don't think of JSX elements as "instances" of actual HTML elements. Think of them as a simple means of how you want your app to look in relation to your state. If my state is "a", then I render a select with "a", and if my state is "b", then I render a select with "b", and so on.
The first select box on the page is only rendered in the constructor which is called just once, thus the component will always remain the same as it does when it is first rendered. In other words it is static. The second select box is going to be re-rendered each time the component is updated.
In order to fix your code you can change your line in the constructor to a function:
this.select = () => (
<select
value={this.state.icecream}
onChange={this.onChange}
>
<option value="chocolate">Chocolate</option>
<option value="vanilla">Vanilla</option>
<option value="strawberry">Strawberry</option>
</select>
);
Then change your return statement to call this function:
<br />
{this.select()}
<br />
I am working on a React project where a list of books will be retrieved from the server.Each book has an option to be set into different shelves, like 1) Currently reading, 2) Want to read and 3) Read based on the user's experience with the book.Each book will have a dropdown where the 3 shelves will be mentioned.Once the user clicks on a shelf from the dropdown,the book will be shown on the selected shelf.So, I am able to retrieve the books from the API, but I am stuck at the point where the books will be set to the respective shelf once it is selected.
Code to retrieve all the books from the API:
import React, { Component } from 'react';
class BooksList extends Component {
state={
showSearchPage: false,
books: [],
selectedValue: 'None'
}
handleChange =(e) => {
this.setState({ selectedValue:e.target.value })
}
render() {
return(
{<div className="book-search">
{this.props.books.map( book =>
<div className="book">
<div className="book-top">
<div className="book-cover" style={{ width: 128, height: 193,margin:10, backgroundImage: `url(${book.imageLinks.smallThumbnail})` }}></div>
<div className="book-shelf-changer">
<select
value={this.state.selectedValue}
onChange={this.handleChange}>
<option value="none" disabled> Move to...</option>
<option value="currentlyReading">✔ Currently Reading</option>
<option value="wantToRead"> Want to Read</option>
<option selected="selected" value="read"> Read</option>
<option value="none"> None</option>
</select>
</div>
</div>
<div className="book-title">{book.title}</div>
<div className="book-authors">{book.authors}</div>
<p>{this.state.selectedValue}</p>
</div>
)}
</div>
}
Code for the Currently Reading shelf:
<div className="list-books-content">
<div>
<div className="bookshelf">
<h2 className="bookshelf-title">Currently Reading</h2>
<div className="bookshelf-books">
<ol className="books-grid">
{ this.props.books.map(book =>
<li>
<div className="book">
<div className="book-top">
<div className="book-cover" style={{ width: 128, height: 193, backgroundImage: `url(${book.imageLinks.smallThumbnail})` }}></div>
<div className="book-shelf-changer">
<select
value={this.state.selectedValue}
onChange={this.handleChange}>
<option value="none" disabled> Move to...</option>
<option value="currentlyReading">✔ Currently Reading</option>
<option value="wantToRead"> Want to Read</option>
<option selected="selected" value="read"> Read</option>
<option value="none"> None</option>
</select>
<p>{this.state.selectedValue}</p>
</div>
</div>
<div className="book-title">{this.state.currentlyReadingBooks}</div>
<div className="book-authors">{book.authors}</div>
</div>
</li>
)}
So what I was thinking of as a solution is : Do we have to create 3 arrays of books for three different sections and move the books to each section.Can anyone please help me with this.I am really stuck with this.I am not able to figure out how to proceed.
Once the user clicks on a shelf from the dropdown,the book will be shown on the selected shelf
This tells me that you probably don't need to store selectedValue in the react state; as soon as a dropdown action action is selected, simply "add" it.
So yes, I think what you describe makes sense - have three seperate arrays of books stored in the react state, and then in your handleChange function, append the book to the appropriate array.
(Side note: best practice in react is to copy the only array from your state instead of directly appending/mutating it.)
I'm using react and I want to get the value of the selected option of a dropdown in react but I don't know how. Any suggestions? thanks!
My dropdown is just a select like:
<select id = "dropdown">
<option value="N/A">N/A</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
The code in the render method represents the component at any given time.
If you do something like this, the user won't be able to make selections using the form control:
<select value="Radish">
<option value="Orange">Orange</option>
<option value="Radish">Radish</option>
<option value="Cherry">Cherry</option>
</select>
So there are two solutions for working with forms controls:
Controlled Components Use component state to reflect the user's selections. This provides the most control, since any changes you make to state will be reflected in the component's rendering:
example:
var FruitSelector = React.createClass({
getInitialState:function(){
return {selectValue:'Radish'};
},
handleChange:function(e){
this.setState({selectValue:e.target.value});
},
render: function() {
var message='You selected '+this.state.selectValue;
return (
<div>
<select
value={this.state.selectValue}
onChange={this.handleChange}
>
<option value="Orange">Orange</option>
<option value="Radish">Radish</option>
<option value="Cherry">Cherry</option>
</select>
<p>{message}</p>
</div>
);
}
});
React.render(<FruitSelector name="World" />, document.body);
JSFiddle: http://jsfiddle.net/xe5ypghv/
Uncontrolled Components The other option is to not control the value and simply respond to onChange events. In this case you can use the defaultValue prop to set an initial value.
<div>
<select defaultValue={this.state.selectValue}
onChange={this.handleChange}
>
<option value="Orange">Orange</option>
<option value="Radish">Radish</option>
<option value="Cherry">Cherry</option>
</select>
<p>{message}</p>
</div>
http://jsfiddle.net/kb3gN/10396/
The docs for this are great: http://facebook.github.io/react/docs/forms.html
and also show how to work with multiple selections.
UPDATE
A variant of Option 1 (using a controlled component) is to use Redux and React-Redux to create a container component. This involves connect and a mapStateToProps function, which is easier than it sounds but probably overkill if you're just starting out.
Implement your Dropdown as
<select id = "dropdown" ref = {(input)=> this.menu = input}>
<option value="N/A">N/A</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
Now, to obtain the selected option value of the dropdown menu just use:
let res = this.menu.value;
It should be like:
import React, { useState } from "react";
export default function App() {
const getInitialState = () => {
const value = "Orange";
return value;
};
const [value, setValue] = useState(getInitialState);
const handleChange = (e) => {
setValue(e.target.value);
};
return (
<div>
<select value={value} onChange={handleChange}>
<option value="Orange">Orange</option>
<option value="Radish">Radish</option>
<option value="Cherry">Cherry</option>
</select>
<p>{`You selected ${value}`}</p>
</div>
);
}
you can see it here: https://codesandbox.io/s/quizzical-https-t1ovo?file=/src/App.js:0-572
Just use onChange event of the <select> object.
Selected value is in e.target.value then.
By the way, it's a bad practice to use id="...". It's better to use ref=">.."
http://facebook.github.io/react/docs/more-about-refs.html
As for front-end developer many time we are dealing with the forms in which we have to handle the dropdowns and we have to
use the value of selected dropdown to perform some action or the send the value on the Server, it's very simple
you have to write the simple dropdown in HTML just put the one onChange method for the selection in the dropdown
whenever user change the value of dropdown set that value to state so you can easily access it in AvFeaturedPlayList
1
remember you will always get the result as option value and not the dropdown text which is displayed on the screen
import React, { Component } from "react";
import { Server } from "net";
class InlineStyle extends Component {
constructor(props) {
super(props);
this.state = {
selectValue: ""
};
this.handleDropdownChange = this.handleDropdownChange.bind(this);
}
handleDropdownChange(e) {
this.setState({ selectValue: e.target.value });
}
render() {
return (
<div>
<div>
<div>
<select id="dropdown" onChange={this.handleDropdownChange}>
<option value="N/A">N/A</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
</div>
<div>Selected value is : {this.state.selectValue}</div>
</div>
</div>
);
}
}
export default InlineStyle;
Using React Functional Components:
const [option,setOption] = useState()
function handleChange(event){
setOption(event.target.value)
}
<select name='option' onChange={handleChange}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
import React from 'react';
import Select from 'react-select';
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
];
class App extends React.Component {
state = {
selectedOption: null,
};
handleChange = selectedOption => {
this.setState({ selectedOption });
console.log(`Option selected:`, selectedOption);
};
render() {
const { selectedOption } = this.state;
return (
<Select
value={selectedOption}
onChange={this.handleChange}
options={options}
/>
);
}
}
And you can check it out on this site.
It is as simple as that. You just need to use "value" attributes instead of "defaultValue" or you can keep both if a pre-selected feature is there.
....
const [currentValue, setCurrentValue] = useState(2);
<select id = "dropdown" value={currentValue} defaultValue={currentValue}>
<option value="N/A">N/A</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
.....
setTimeut(()=> {
setCurrentValue(4);
}, 4000);
In this case, after 4 secs the dropdown will be auto-selected with option 4.
I was making a drop-down menu for a language selector - but I needed the dropdown menu to display the current language upon page load. I would either be getting my initial language from a URL param example.com?user_language=fr, or detecting it from the user’s browser settings. Then when the user interacted with the dropdown, the selected language would be updated and the language selector dropdown would display the currently selected language.
In the spirit of the other answers using food examples, I got all sorts of fruit goodness for you.
First up, answering the initially asked question with a basic React functional component - two examples with and without props, then how to import the component elsewhere.
Next up, the same example - but juiced up with Typescript.
Then a bonus finale - A language selector dropdown component using Typescript.
Basic React (16.13.1) Functional Component Example. Two examples of FruitSelectDropdown , one without props & one with accepting props fruitDetector
import React, { useState } from 'react'
export const FruitSelectDropdown = () => {
const [currentFruit, setCurrentFruit] = useState('oranges')
const changeFruit = (newFruit) => {
setCurrentFruit(newFruit)
}
return (
<form>
<select
onChange={(event) => changeFruit(event.target.value)}
value={currentFruit}
>
<option value="apples">Red Apples</option>
<option value="oranges">Outrageous Oranges</option>
<option value="tomatoes">Technically a Fruit Tomatoes</option>
<option value="bananas">Bodacious Bananas</option>
</select>
</form>
)
}
Or you can have FruitSelectDropdown accept props, maybe you have a function that outputs a string, you can pass it through using the fruitDetector prop
import React, { useState } from 'react'
export const FruitSelectDropdown = ({ fruitDetector }) => {
const [currentFruit, setCurrentFruit] = useState(fruitDetector)
const changeFruit = (newFruit) => {
setCurrentFruit(newFruit)
}
return (
<form>
<select
onChange={(event) => changeFruit(event.target.value)}
value={currentFruit}
>
<option value="apples">Red Apples</option>
<option value="oranges">Outrageous Oranges</option>
<option value="tomatoes">Technically a Fruit Tomatoes</option>
<option value="bananas">Bodacious Bananas</option>
</select>
</form>
)
}
Then import the FruitSelectDropdown elsewhere in your app
import React from 'react'
import { FruitSelectDropdown } from '../path/to/FruitSelectDropdown'
const App = () => {
return (
<div className="page-container">
<h1 className="header">A webpage about fruit</h1>
<div className="section-container">
<h2>Pick your favorite fruit</h2>
<FruitSelectDropdown fruitDetector='bananas' />
</div>
</div>
)
}
export default App
FruitSelectDropdown with Typescript
import React, { FC, useState } from 'react'
type FruitProps = {
fruitDetector: string;
}
export const FruitSelectDropdown: FC<FruitProps> = ({ fruitDetector }) => {
const [currentFruit, setCurrentFruit] = useState(fruitDetector)
const changeFruit = (newFruit: string): void => {
setCurrentFruit(newFruit)
}
return (
<form>
<select
onChange={(event) => changeFruit(event.target.value)}
value={currentFruit}
>
<option value="apples">Red Apples</option>
<option value="oranges">Outrageous Oranges</option>
<option value="tomatoes">Technically a Fruit Tomatoes</option>
<option value="bananas">Bodacious Bananas</option>
</select>
</form>
)
}
Then import the FruitSelectDropdown elsewhere in your app
import React, { FC } from 'react'
import { FruitSelectDropdown } from '../path/to/FruitSelectDropdown'
const App: FC = () => {
return (
<div className="page-container">
<h1 className="header">A webpage about fruit</h1>
<div className="section-container">
<h2>Pick your favorite fruit</h2>
<FruitSelectDropdown fruitDetector='bananas' />
</div>
</div>
)
}
export default App
Bonus Round: Translation Dropdown with selected current value:
import React, { FC, useState } from 'react'
import { useTranslation } from 'react-i18next'
export const LanguageSelectDropdown: FC = () => {
const { i18n } = useTranslation()
const i18nLanguage = i18n.language
const [currentI18nLanguage, setCurrentI18nLanguage] = useState(i18nLanguage)
const changeLanguage = (language: string): void => {
i18n.changeLanguage(language)
setCurrentI18nLanguage(language)
}
return (
<form>
<select
onChange={(event) => changeLanguage(event.target.value)}
value={currentI18nLanguage}
>
<option value="en">English</option>
<option value="de">Deutsch</option>
<option value="es">Español</option>
<option value="fr">Français</option>
</select>
</form>
)
}
An invaluable resource for React/Typescript
You can handle it all within the same function as following
<select className="form-control mb-3" onChange={(e) => this.setState({productPrice: e.target.value})}>
<option value="5">5 dollars</option>
<option value="10">10 dollars</option>
</select>
as you can see when the user select one option it will set a state and get the value of the selected event without furder coding require!
If you want to get value from a mapped select input then you can refer to this example:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
fruit: "banana",
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
console.log("Fruit Selected!!");
this.setState({ fruit: e.target.value });
}
render() {
return (
<div id="App">
<div className="select-container">
<select value={this.state.fruit} onChange={this.handleChange}>
{options.map((option) => (
<option value={option.value}>{option.label}</option>
))}
</select>
</div>
</div>
);
}
}
export default App;
import {React, useState }from "react";
function DropDown() {
const [dropValue, setDropValue ]= useState();
return <>
<div>
<div class="dropdown">
<button class="btn btn-secondary" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">
{dropValue==null || dropValue=='' ?'Select Id':dropValue}
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
<li><a class="dropdown-item" onClick={()=> setDropValue('Action')} href="#">Action</a></li>
<li><a class="dropdown-item" onClick={()=> setDropValue('Another action')} href="#">Another action</a></li>
<li><a class="dropdown-item" onClick={()=> setDropValue('Something else here')} href="#">Something else here</a></li>
</ul>
</div>
</div>
</>
}
export default DropDown
<select value ={this.state.value} onChange={this.handleDropdownChange}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
As mentioned by Karen above you can just use the target value from the event triggered. Here is a small snippet of the code
`<select class="form-select py-2"
onChange={(e) => setVotersPerPage(e.target.value)}>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
</select>`