I have a list in React where I’m using .map
to render a loop from an array of elements.
The radio inputs are working perfectly, everyone is independent of the others, but I can’t do the same for Select
.
The Select
area is changing in every field, I want it to change to it specified field like I did for the options.
I tried to re-use the same handleChange
that I used in the radios for it and instead I had this error.
Cannot set property 'animation' of undefined
In this line
newAnimations[indexurl].animation = name;
How do I manage to separate the selects
?
Note: This code is working fine, but it’s updating the value on every field.
const onChange = (animations) => { setAnimations(animations); console.log(`Animation selected:`, animations); };
Code : https://codesandbox.io/s/dank-violet-jibzh?file=/src/App.js:1065-1194
import React, { useState } from "react"; import Select from "react-select"; export default () => { const animationsList = [ { value: "animation0", label: "Dance" }, { value: "animation1", label: "Flip" }, { value: "animation2", label: "Salsa" } ]; const reactList = [ { id: "14444", selected: "layout3", animation: "animation1" }, { id: "24444", selected: "layout3", animation: "animation2" }, { id: "34444", selected: "layout3", animation: "animation1" } ]; const [links, setLinks] = useState(reactList); const [animations, setAnimations] = useState(animationsList[0]); const handleChangeSelectedReact = (indexurl, layout) => { const cloneLinks = [...links]; cloneLinks[indexurl].selected = layout; setLinks(cloneLinks); console.log(cloneLinks); }; /* const onChange = (animations) => { setAnimations(animations); console.log(`Animation selected:`, animations); };*/ const onChange = (indexurl, name) => { const newAnimations = [...links]; newAnimations[indexurl].animation = name; setAnimations(newAnimations); console.log(newAnimations); }; return ( <div> <ul> <div> {links.map((url, indexurl) => ( <li key={url.id}> <div> <Select options={animationsList} onChange={onChange} value={animations} /> <p />{" "} <input type="radio" id={url.id} name={url.id} value="layout1" checked={url.selected === "layout1"} onChange={() => handleChangeSelectedReact(indexurl, "layout1") } /> <label for="huey">Option 1</label> </div> <div> <input type="radio" id={url.id} name={url.id} value="layout2" checked={url.selected === "layout2"} onChange={() => handleChangeSelectedReact(indexurl, "layout2") } /> <label for="dewey">Option 2</label> </div> <div> <input type="radio" id={url.id} name={url.id} value="layout3" checked={url.selected === "layout3"} onChange={() => handleChangeSelectedReact(indexurl, "layout3") } /> <label for="louie">Option 3</label> </div> <br /> </li> ))} </div> </ul> </div> ); };
Advertisement
Answer
Multiple Selects share the same state, resulting in updates the value on every field. So we need to wrap Select into components and maintain their own state independently:
function SelectItem({ list }) { const [value, setValue] = React.useState(list[0]); const onChange = (newValue) => { setValue(newValue); }; return <Select options={list} onChange={onChange} value={value} />; }
... ... return ( <div> {links.map((url, indexurl) => ( <SelectItem list={animationsList} /> ))} </div> ); ... ...
Update
Modify the links
when select
is selected:
function SelectItem(props) { const [value, setValue] = React.useState(props.list[0]); return ( <Select options={props.list} onChange={(newValue) => { setValue(newValue); props.onChange(newValue.value); }} value={value} /> ); }
... ... const onChange = (index, animation) => { const cloneLinks = [...links]; cloneLinks[index].animation = animation; setLinks(cloneLinks); console.log(cloneLinks); }; return ( <div> {links.map((url, indexurl) => ( <SelectItem onChange={(animation) => onChange(indexurl, animation)} list={animationsList} /> ))} </div> ); ... ...
Full code: https://codesandbox.io/s/happy-cloud-m6z99?file=/src/App.js:77-298