How to find the specific item from items when using React Select? - reactjs

//value={items.find(x => x.item === selectedValue)}import { Fragment, useState } from //"react";
import Select from 'react-select';
let items = [
{
item: 1,
name: "tv"
},
{
item: 2,
name: "PC"
}
]
const Home = () => {
const [selectedValue, setSelectedValue] = useState(6)
const handleChange = obj => {
setSelectedValue(obj.item)
}
return (
<Fragment>
<div>Home page</div>
<p>Test React Select...</p>
<Select
value={items.find(x => x.item === selectedValue)}
options={items.map(({item, name}) => ({value: name, label: item}))}
onChange={handleChange}
/>
<p>selected Value:...</p>
{selectedValue}
</Fragment>
)
}
export default Home;

It would be helpful if you could provide more information, like if you're getting an error.
However, I think your problem is twofold:
the value of your Select component is being set to the entire object instead of the value.
You've mixed up the value and label keys in the options prop.
Try this:
<Select
value={items.find(x => x.item === selectedValue).item}
options={items.map(({item, name}) => ({value: item, label: name}))}
onChange={handleChange}
/>
EDIT: You don't need to use find, you already have this value:
<Select
value={selectedValue}
options={items.map(({item, name}) => ({value: item, label: name}))}
onChange={handleChange}
/>

Related

How to set default value in Select Component?

On React Carbon Select component I want to have a default selected option, which can be changed, of course.
In general my goal is to implement edit functionality. It means user should be able to change already selected option.
I tried with adding the value property directly in Select like value={defaultSelected} or defaultValue={defaultSelected} but it didn't work.
Code example.
import React, { useState } from 'react';
import { Select, SelectItem } from '#carbon/react';
const options = [
{
value: 'apple',
text: 'Apple 🍏',
},
{
value: 'banana',
text: 'Banana 🍌',
},
{
value: 'kiwi',
text: 'Kiwi 🥝',
},
];
const SelectCarbon = ({defaultSelected}) => {
const [formData, setFormData] = useState();
const onChange = e => {
setFormData({
...formData,
fruit: e.target.value,
});
};
console.log('formData', formData);
return (
<>
{defaultSelected}
<Select id="select-fruits" onChange={onChange} value={defaultSelected}>
<SelectItem text="select Option" value="" />
{options.map(option => (
<SelectItem
key={option.value}
text={option.value}
value={option.value}
/>
))}
</Select>
</>
);
};
export default SelectCarbon;
Any help will be appreciated
Try This
const [formData, setFormData] = useState({
fruit: options[0].value
});
And note that formDate should be an object not array.
I came up with this solution conditionally showing either default value if nothing is selected or selected value.
And in order show the default value initially, I wrapped in formData in useEffect.
React.useEffect(() => {
setFormData({
...formData,
fruit: defaultSelected,
});
}, [defaultSelected]);
const onChange = e => {
setFormData({
...formData,
fruit: e.target.value ?? defaultSelected,
});
};
console.log('formData', formData);
return (
<>
{defaultSelected}
<Select
id="select-fruits"
onChange={onChange}
defaultValue={defaultSelected}>
<SelectItem text="select Option" value="" />
{options.map(option => (
<SelectItem
key={option.value}
text={option.value}
value={option.value}
/>
))}
</Select>
</>
);
};
export default SelectCarbon;

Default value with react-select, checkboxes not working when I want to post my data having a blank page output

I'm not able to put my fetch data as a defaultValue in my Dropdown (react-select) and Checkboxe? I have the displayed dropdown ("Good",...) but the defaultValue for the dishId:1 is Medium, so I'm supposed to see Medium already selected in my Dropdown, which is not the case (same issue for comment).
export default function MenuItemDisplay() {
...
const [dish, setDish] = useState([])
useEffect(() => {
axios.post(url, { dishId })
.then(res => {
console.log(res)
setDish(res.data.dishes [0])
})
.catch(err => {
console.log(err)
})
}, [dishId]);
const TASTE = [
{ label: "Good", value: "Good" },
{ label: "Medium", value: "Medium" },
{ label: "Bad", value: "Bad" }
];
const COMMENT = [
{ label: "0", value: "0" },
...
];
function Checkbox({ value }) {
const [checked, setChecked] = React.useState(true);
return (
<label>
<input
type="checkbox"
defaultChecked={checked}
onChange={() => setChecked(!checked)}
/>
{value}
</label>
);
}
return (
<>
<Dropdown
style={styles.select}
options={TASTE}
defaultValue={TASTE.find((t) => t.label === dish.taste)}
isMulti={true}
/>
<Dropdown
style={styles.select}
options={COMMENT}
defaultValue={TASTE.find((t) => t.label === dish.comment)}
isMulti={true}
/>
<Checkbox value={!!dish.trust} />
{(dish.menu) !== "") ?
<div>
Menu
<div >
{dish.menu}
</div>
</div>
: ""
}
</>
);
}
export default function CustomDropdown({
className,
style,
options,
styleSelect,
value,
setValue,
isMulti = false
}) {
const styles = {
select: {
width: "100%",
maxWidth: 200
}
};
function changeSelect(option) {
setValue(option.value);
}
return (
<div style={style} onClick={(e) => e.preventDefault()}>
{value && isMulti === false ? (
<Tag
selected={value}
setSelected={setValue}
styleSelect={styleSelect}
/>
) : (
<Select
className={className}
style={styles.select}
value={value}
onChange={changeSelect}
options={options}
isMulti={isMulti}
/>
)}
</div>
);
}
export default function Tag({ selected, setSelected, styleSelect }) {
const backgroundColor = styleSelect?.(selected?.label) ?? "grey";
return (
<div style={{
display: "flex",
justifyContent: "space-around",
padding: "0.1em",
backgroundColor: backgroundColor,
borderRadius: "4px",
color: "white",
marginRight: "20px",
marginLeft: "4px",
marginBottom: "8px"
}}>
{selected}
<button
style={{...}}
onClick={() => setSelected(null)}
>x</button>
</div>
)
}
I really don't understand why is it not working since dish.taste returns me "Medium", dish.comment returns me 5, dish.trust give me 1.
What's wrong with my Dropdown and/or Tag component?
Here there should be the main problem:
<Dropdown
defaultValue={TASTE.find((t) => t.label === dish.taste)}
/>
With this defaultValue prop you are only setting the value once, when the dropdown renders. The dish.taste can not be defined at that time if you retrieve its value through an async request. What you should do instead is adding a useEffect that sets the right value of the dropdown only after it has defined the dish.taste value. So:
const [valueDropdown, setValueDropdown] = React.useState(null);
useEffect(() => {
// here you are running this useEffect each time the dish state changes
if(dish?.taste){ //checks if taste exists
setValueDropdown(TASTE.find((t) => t.label === dish.taste));
}
}, [dish]);
Now, instead of passing to the dropdown the defaultValue you should pass two new props: the value and the setValue:
<Dropdown
value={valueDropdown}
setValue={setValueDropdown}
/>
Lastly, with the change of the props you should also update them inside the Dropdown component and remove the state definition inside that component:
export default function CustomDropdown({
style,
options,
styleSelect,
value : selected,
setValue : setSelected
}) {
// remove the line const [selected, setSelected] = useState(defaultValue);
....other logic
}
A possible fix:
<Dropdown
style={styles.select}
options={TASTE}
defaultValue={TASTE.find((t) => t.label === dish.find((d) => d.id === dishId))}
isMulti={true}
/>
The other part I could not undestand what you're trying to do, but it is wrong. As Cristiano replyied, you are comparing different types using !==, so it will never be a true condition. Maybe use the same fix as above?
(dish.find((d) => d.id === dishId).menu !== "")
EDIT AND REEDIT
Given more information, this could fix:
export default function MenuItemDisplay() {
...
const [dish, setDish] = useState(null)
useEffect(() => {
axios.post(url, { dishId })
.then(res => {
console.log(res)
// make your dish variable not array
setDish(res.data.dishes[0])
})
.catch(err => {
console.log(err)
})
}, [dishId]);
const TASTE = [
{ label: "Good", value: "Good" },
{ label: "Medium", value: "Medium" },
{ label: "Bad", value: "Bad" }
];
if (!dish) {
return (
<div>Loading</div>
);
}
return (
<>
<Dropdown
style={styles.select}
options={TASTE}
// remove map cuz it is not array
defaultValue={TASTE.find((t) => t.label === dish.taste)}
isMulti={true}
/>
{/* remove map cuz it is not array */}
{dish.menu !== "") ?
<div>
Menu
<div >
{question.map((e) => e.menu)}
</div>
</div>
: ""
}
</>
);
}
You are comparing a string (t.label) using === operator with array (result of dish.map) in defaultValue definition.
Try to change it.
Issue
I think the issue is simply that that defaultValue prop of a React component is expected to exist when the component mounts and never change. It's the default value when the component mounts. The code in your example is comparing an element in the TASTE array against the initial dish state, which is an array but accessed as an object. dish.taste of [] is undefined.
Solutions
Uncontrolled Component
If you want the Dropdown component to remain an uncontrolled component then it should be conditionally rendered only when the dish state has been initialized by the useEffect hook and the POST request.
const [dish, setDish] = useState(); // initially undefined
useEffect(() => {
axios.post(url, { dishId })
.then(res => {
console.log(res)
setDish(res.data.dishes[0]);
})
.catch(err => {
console.log(err);
});
}, [dishId]);
...
{dish.taste && ( // conditionally render the dropdown
<Dropdown
style={styles.select}
options={TASTE}
defaultValue={TASTE.find((t) => t.label === dish.taste)}
isMulti
/>
)}
Controlled Component
If you want the Dropdown component to be controlled, then use the (likely) value prop instead. It's meant to be changed during the life of the component.
const [dish, setDish] = useState(); // initially undefined
useEffect(() => {
axios.post(url, { dishId })
.then(res => {
console.log(res)
setDish(res.data.dishes[0]);
})
.catch(err => {
console.log(err);
});
}, [dishId]);
...
<Dropdown
style={styles.select}
options={TASTE}
value={TASTE.find((t) => t.label === dish.taste)} // use value prop
isMulti
/>

react.js react-select onselected value change another select value and submit multiple items to array

I have stomped on a problem that i don't know how to resolve.
I have a react-select input that passes a selected value to another select input.
When a user clicks on submit button then i have to display an array of every selector input that the user has selected as a list of items and then the form should reset all select values.
For this, i have tried submitting to an array but it only shows one item from all selectors and form doesn't reset its values.
Here is a sandbox link
https://codesandbox.io/s/awesome-carson-i99g8p?file=/src/App.js
How can I archive this I have tried everything but I could not figure out how can i archive this functionality.
Ok. First tricky thing of react-select is, the value you assign to the component must be an object with label and valueproperties, not just the value. Meaning, when handling change events, you should set the state using the full event object.
This is the code mostly fixed:
import React, { useState, useEffect } from "react";
import Select from "react-select";
const options = [
{ value: "0", label: "0" },
{ value: "1", label: "1" },
{ value: "2", label: "2" }
];
const options2 = [
{ value: "Before Due Date", label: "Before Due Date" },
{ value: "After Due Date", label: "After Due Date" }
];
const App = (props) => {
const [numOfDays, setNumOfDays] = useState('');
const [beforeDueDate, setBeforeDueDate] = useState('');
const [items, setItems] = useState([]);
const [reminders, setReminders] = useState([]);
const submit = (event) => {
event.preventDefault(); // <-- prevent form submit action
const obj = {};
obj.id = reminders.length + 1;
obj.numOfDays = numOfDays.value;
obj.beforeDueDate = beforeDueDate.value;
setReminders((items) => [...items, obj]); // <-- update arr state
setBeforeDueDate("");
setNumOfDays("");
};
function numOfDaysHandle(event) {
// const numOfDays = event.value;
setNumOfDays(event);
setItems((items) => [...items, items]);
}
function beforeDueDateHandle(event) {
// const value = event.value;
setBeforeDueDate(event);
}
const removeReminder = (id) => {
setReminders(reminders.filter((item) => item.id !== id));
};
return (
<>
<form>
<div>
{reminders.map((item, index) => (
<div key={index}>
<div>
<span>
{item.numOfDays} days {item.beforeDueDate}
</span>
<button onClick={() => removeReminder(item.id)}>
removeItem
</button>
</div>
</div>
))}
</div>
<div>
<Select
options={options}
value={numOfDays}
id="numOfDays"
placeholder="Days"
isSearchable={false}
//onChange={numOfDaysHandle}
onChange={numOfDaysHandle}
/>
<Select
options={options2}
value={beforeDueDate}
id="beforeDueDate"
placeholder="Before Due Date"
isSearchable={false}
onChange={beforeDueDateHandle}
/>
</div>
{items.map((item, index) => (
<div key={index}>
<Select
options={options}
value={item.numOfDays}
id="numOfDays"
placeholder="Days"
isSearchable={false}
onChange={numOfDaysHandle}
/>
<Select
options={options2}
value={item.beforeDueDate}
id="beforeDueDate"
placeholder="Before Due Date"
isSearchable={false}
onChange={beforeDueDateHandle}
// onClick={() => setItems((items) => [...items, items])}
/>
</div>
))}
<button
onClick={submit}
//disabled={!numOfDays}
>
Set Reminder
</button>
</form>
</>
);
};
export default App;
Please see if you can move forward now, I could not understand what you want exactly with the array of <Select /> elements.

Dependant Select Components not showing the Selected Value in Input Field

There are 4 select Components with dependant dropdown menu.But when I select an option its not displaying in the input field although my 'selectedPlanets' state is updating just right.
Here is my code -
import React, { useState } from "react";
import "../css/Destination.css";
function Destination(props) {
const [selectedPlanets, SetselectedPlanets] = useState([
null,
null,
null,
null,
]);
const OnSelectPlanet = async (e, key) => {
const clonedSelectedPlanets = JSON.parse(JSON.stringify(selectedPlanets));
clonedSelectedPlanets[key] = e.target.value;
SetselectedPlanets(clonedSelectedPlanets);
};
const CustomSelectComponents = ({ value, options, OnSelect}) => {
return (
<select value={value} onChange={OnSelect}>
<option> -- Select a Planet -- </option>
{options.map((option) => {
return <option key = {option.name} value={option.name} >{option.name}</option>;
})}
</select>
);
};
const OptionsToRender = (Alloptions, AllselectedOptions, index) => {
console.log(AllselectedOptions);
const optionstoRender =
AllselectedOptions[index] != null
? Alloptions.filter(
(option) =>
!AllselectedOptions.some(
(selectedOption) =>
option && selectedOption && option.name === selectedOption
)
)
: Alloptions;
return optionstoRender;
};
return (
<>
<div className="Parent_Card">
{selectedPlanets.map((planet, index) => {
const options = OptionsToRender(props.planets, selectedPlanets, index);
return (
<>
{console.log(index)}
<CustomSelectComponents
value={
selectedPlanets[index] != null ? selectedPlanets[index] : ""
}
options={options}
OnSelect={(e) => OnSelectPlanet(e, index)}
key={index}
/>
</>
);
})}
</div>
</>
);
}
export default Destination;
I tried debugging it and figured that its maybe because of how and when my component is rendering.But I dont know why and hence not able to find the solution.
My expected result is when I am choosing an option it shows in the input field.
Your code could benefit from a few different approaches to building your 4 different select components:
the use of controlled components
(https://reactjs.org/docs/forms.html#controlled-components)
separating the state for each of the different selects
refactoring the <CustomSelectComponent /> to be a component that only accepts props
Here is an example of those approaches in practice that might provide some direction on getting these selects operating as expected!
import React, { useState } from 'react';
import '../css/Destination.css';
// custom select component
const CustomSelectComponent = ({ onChange, options, value }) => (
<select onChange={onChange} value={value}>
<option> -- Select a Planet -- </option>
{options.map(option => (
<option key={option.name} value={option.name}>
{option.name}
</option>
))}
</select>
);
const Destination = () => {
// mock props
const props = { planets: [{ name: 'Pluto' }, { name: 'Earth' }] };
// separated state
const [selectOneValue, setSelectOneValue] = useState('');
const [selectTwoValue, setSelectTwoValue] = useState('');
const [selectThreeValue, setSelectThreeValue] = useState('');
const [selectFourValue, setSelectFourValue] = useState('');
return (
<div className="Parent_Card">
{/* each custom select component is now controlled by it's own state */}
<CustomSelectComponent
onChange={e => setSelectOneValue(e.target.value)}
options={props.planets}
value={selectOneValue}
/>
<CustomSelectComponent
onChange={e => setSelectTwoValue(e.target.value)}
options={props.planets}
value={selectTwoValue}
/>
<CustomSelectComponent
onChange={e => setSelectThreeValue(e.target.value)}
options={props.planets}
value={selectThreeValue}
/>
<CustomSelectComponent
onChange={e => setSelectFourValue(e.target.value)}
options={props.planets}
value={selectFourValue}
/>
</div>
);
};
export default Destination;

React: Why is one of my prop variable undefined?

Hey I'm new to React and I'm having a problem with my prop which I'm passing to my ChildComponent. I am using "react-select" and have two multiselects. Originally I wanted to show in each select the value for the corresponding select I get from the state.
value={optionsColor.filter(item => ( myTest.color.includes(item.value)))}
But this is not possible because one of my calls is always "undefined". For example "myTest.Color" and "myTest.Car" one of them is "undefined" but I don't know why?
In my code (ChildComponent) I have two console.logs which illustrate this.
For example, if I select Color and have previously selected a car in Car, the console.log output looks like this.
undefined
blue
But I want it to output both.
import {useState} from "react";
import ChildComponent from "./ChildComponent";
const ParentComponent = () => {
const [step, setStep] = useState(0)
const [myTest, setMyTest] = useState(
{
color: ['defaultColor'],
car: ['defaultCar'],
}
)
const handleChange = (e, action) => {
setMyTest({ [action.name]: e ? e.map(x => x.value) : [] })
}
return (
<div>
<div className="card-body container mt-3">
<h2>Product data input Intended Use</h2>
<div className="card p-2 mt-5">
<form className="mb-4">
<div className="form"></div>
<ChildComponent myTest={myTest} handleChange={handleChange}/>
</form>
</div>
</div>
</div>
)
}
export default ParentComponent;
import React, { useState } from 'react';
import Select from 'react-select';
const optionsColor = [
{ value: 'blue', label: 'Blue' },
{ value: 'red', label: 'Red' },
{ value: 'yellow', label: 'Yellow' }
]
const optionsCar = [
{ value: 'bmw', label: 'BMW' },
{ value: 'ford', label: 'Ford' },
{ value: 'vw', label: 'VW' },
]
const ChildComponent = ({ handleChange, myTest}) => {
return (
<div>
<h4>Car {console.log(myTest.car)}</h4>
<Select
name="car"
options={optionsCar}
className="mb-3"
onChange={handleChange}
//value={intendedUse.sex === undefined ? '' : optionsSex.filter(item => (intendedUse.sex.includes(item.value)))}
isMulti
autoFocus
isSearchable
/>
<h4>Color {console.log(myTest.color)}</h4>
<Select
name="color"
options={optionsColor}
className="mb-3"
onChange={handleChange}
//value={intendedUse.age === undefined ? '': optionsAge.filter(item => ( intendedUse.age.includes(item.value)))}
isMulti
autoFocus
isSearchable
/>
</div>
)
}
export default ChildComponent;
the problem lies here.
setMyTest({ [action.name]: e ? e.map(x => x.value) : [] })
When you're updating your myTest state you're actually replacing both of the fields with the field you're setting.
Try something like this:
setMyTest(myTest => ({...myTest, { [action.name]: e ? e.map(x => x.value) : [] }}));
In that way, you have a new object with both the field that changed and the one that didn't.

Resources