Onchange event in select should change others inputs field value? - reactjs

As a Begineer in a react,here what i want to do is when i select options from the react-select option the i want to dispaly that selected options label in the text input down above on both field but got problem with here onchanges event How to change value in text field from the select options along with selected value?
Code
import React, { useState } from "react";
const initialValues = [{ number: "", options: "" }];
const countries = [
{ id: 1, name: USA },
{ id: 2, name: Russia },
{ id: 3, name: UK },
];
const Newrow = (props) => {
const [number, setNumber] = useState("");
const [options, setoption] = useState([]);
const [options1, setoption1] = useState("");
const addRow = () => {
let _row = {
number: "",
options: "",
};
props.setData(_row);
};
return (
<div>
<input
type="number"
value={number}
onChange={(e) => {
setNumber(e.target.value);
}}
/>
<input
type="text"
className="input"
value={options}
onChange={options1}
/>
<input
type="text"
className="input"
value={options}
onChange={options1}
/>
</div>
);
};
export default function App(props) {
const [data, setData] = useState([]);
const addRow = (row) => {
setData([...data, row]);
};
return (
<div className="App">
<Select
options={countries}
value={{
label: name,
value: id,
}}
onChange={(e) => {
const res = {
id: e.value,
name: e.label,
};
console.log(res);
setoption1(res);
}}
></Select>
{[...data, ...initialValues].map((row, idx) => {
return (
<Newrow
setData={addRow}
data={row}
key={idx}
delrow={idx}
options1={options1}
/>
);
})}
<button
type="submit"
onClick={() => addRow({ number: "", options: "" })}
className="btn btn-success"
>
Add
</button>
</div>
);
}

You appear to be passing in options1 (a string) into the onChange handler of your text inputs. The onChange handler should only take a function, that will be triggered when those inputs change.
You can discard the onChange={options1} property and change the value property to value={options1}.
Change this:
<input type="text"
className="input"
value={options}
onChange={options1}
/>
to this:
<input type="text"
className="input"
value={options1}
/>

Related

how to get value in dynamic input to sql React

I'm a newbie react.I had generated input fields dynamically. Now I want to get values firstName and Lastname in this dynamics input fields to the database but I don't know how to get this value.
please help me
his my code App.js
import React, { useState } from "react";
function App() {
const [inputList, setInputList] = useState([{ firstName: "", lastName: "" }]);
const handleInputChange = (e, index) => {
const { name, value } = e.target;
const list = [...inputList];
list[index][name] = value;
setInputList(list);
};
const handleAddClick = () => {
setInputList([...inputList, { firstName: "", lastName: "" }]);
};
return (
<div className="App">
{inputList.map((x, i) => {
return (
<div className="box">
<input
name="firstName"
placeholder="Enter First Name"
value={x.firstName}
onChange={e => handleInputChange(e, i)}
/>
<input
className="ml10"
name="lastName"
placeholder="Enter Last Name"
value={x.lastName}
onChange={e => handleInputChange(e, i)}
/>
<div className="btn-box">
{inputList.length - 1 === i && <button onClick={handleAddClick}>Add</button>}
</div>
</div>
);
})}
<div style={{ marginTop: 20 }}>{JSON.stringify(inputList)}</div>
</div>
);
}
export default App;
Thank you
You need to retrieve values from server side which means you will do fetch process in browser side. Use useEffect to do fetch call and set the response with setInputList.
The below is one way with useEffect. Depending on your pj concept, you can also use useSwr, SSR or etc where data retrieving happens.
import React, { useState, useEffect } from "react";
function App() {
const [inputList, setInputList] = useState([{ firstName: "", lastName: "" }]);
const handleInputChange = (e, index) => {
const { name, value } = e.target;
const list = [...inputList];
list[index][name] = value;
setInputList(list);
};
const handleAddClick = () => {
setInputList([...inputList, { firstName: "", lastName: "" }]);
};
useEffect(()=>{
let canExexute = true;
// Anything to retrieve data such as
// fetch, graphql query,,,etc
// Set values from the above
if (canExecute) setInputList(values)
// Caring about when unmounting component
return ()=>{
canExecute = false;
}
// Don't put inputList state itself as dependancies which causes infinite rendering.
},[dependencies])
return (
<div className="App">
{inputList.map((x, i) => {
return (
<div className="box">
<input
name="firstName"
placeholder="Enter First Name"
value={x.firstName}
onChange={e => handleInputChange(e, i)}
/>
<input
className="ml10"
name="lastName"
placeholder="Enter Last Name"
value={x.lastName}
onChange={e => handleInputChange(e, i)}
/>
<div className="btn-box">
{inputList.length - 1 === i && <button onClick={handleAddClick}>Add</button>}
</div>
</div>
);
})}
<div style={{ marginTop: 20 }}>{JSON.stringify(inputList)}</div>
</div>
);
}
export default App;

Losing focus on input onChange React

What I'm trying to achieve, it's to create each input as own component.
And I can't get how to fix thing when my app all the time rerendering when I'm pressing any key.
I know if I'll use controlledInputs -> so each input would have it own useState that would work. But the main idea to do that this way
import React, { useState } from 'react';
const ControlledInputs = () => {
const [person, setPerson] = useState({ firstName: '', email: '', age: '' });
const [people, setPeople] = useState([]);
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setPerson({ ...person, [name]: value });
};
const handleSubmit = (e) => {
e.preventDefault();
if (person.firstName && person.email && person.age) {
const newPerson = { ...person, id: new Date().getTime().toString() };
setPeople([...people, newPerson]);
setPerson({ firstName: '', email: '', age: '' });
}
};
function FormControl({number, idname , type , text}){
return(
<div className='form-control'>
<label htmlFor={idname}>{text} : </label>
<input
type={type}
id={idname}
name={idname}
value={person[idname]}
onChange={(e) =>handleChange(e)}
/>
</div>
)
}
return (
<>
<article className='form'>
<form>
<FormControl idname={"firstName"} type={"text"} text={"First name"}/>
<FormControl type={"email"} idname={"email"} text={"Email"}/>
<FormControl type={"age"} idname={"age"} text={"Age"}/>
<button type='submit' className='btn' onClick={handleSubmit}>
add person
</button>
</form>
</article>
<article>
{people.map((person) => {
const { id, firstName, email, age } = person;
return (
<div key={id} className='item'>
<h4>{firstName}</h4>
<p>{email}</p>
<p>{age}</p>
</div>
);
})}
</article>
</>
);
};
export default ControlledInputs;
You need to define the FormControl outside of ControlledInputs, otherwise, React will recreate it and you lose focus as well as data.
And you need to pass value and handleChange as props in FormControl.
Here are codes you can refactor. Please note that the number you defined is not removed.
function FormControl({value, handleChange, idname , type , text}){
return(
<div className='form-control'>
<label htmlFor={idname}>{text} : </label>
<input
type={type}
id={idname}
name={idname}
value={value}
onChange={(e) =>handleChange(e)}
/>
</div>
)
}
Usage in form:
function FormControl({value, handleChange, idname , type , text}){
return(
<div className='form-control'>
<label htmlFor={idname}>{text} : </label>
<input
type={type}
id={idname}
name={idname}
value={value}
onChange={(e) =>handleChange(e)}
/>
</div>
)
}
const ControlledInputs = () => {
const [person, setPerson] = useState({ firstName: '', email: '', age: '' });
const [people, setPeople] = useState([]);
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setPerson({ ...person, [name]: value });
};
const handleSubmit = (e) => {
e.preventDefault();
if (person.firstName && person.email && person.age) {
const newPerson = { ...person, id: new Date().getTime().toString() };
setPeople([...people, newPerson]);
setPerson({ firstName: '', email: '', age: '' });
}
};
return (
<>
<article className='form'>
<form>
<FormControl idname={"firstName"} type={"text"} text={"First name"} value={person['firstName']} handleChange={handleChange}/>
<FormControl type={"email"} idname={"email"} text={"Email"} value={person['email']} handleChange={handleChange}/>
<FormControl type={"age"} idname={"age"} text={"Age"} value={person['age']} handleChange={handleChange}/>
<button type='submit' className='btn' onClick={handleSubmit}>
add person
</button>
</form>
</article>
<article>
{people.map((person) => {
const { id, firstName, email, age } = person;
return (
<div key={id} className='item'>
<h4>{firstName}</h4>
<p>{email}</p>
<p>{age}</p>
</div>
);
})}
</article>
</>
);
};
That is because FormControl is defined inside the ControlledInputs component. So, on each rerender of the ControlledInputs, you create a new FormControl function and that means that React will treat it as a different component than the one in the previous render, and so it will lose focus, as the old one is considered unmounted.
Just define the FormControl outside the other one, and pass it what extra data you need as props, and you should be set.

Two-way data binding on large forms

(After working through a React.js tutorial, I'm currently coding my first little app to get more practice. So this will be a newbie question and the answer is certainly out there somewhere, but apparently I don't know what to search for.)
Google lists a lot of examples on how to achieve two-way data binding for one input field. But what about large, complex forms, possibly with the option of adding more dynamically?
Let's say my form consists of horizontal lines of input fields. All lines are the same: First name, last name, date of birth and so on. At the bottom of the table, there is a button to insert a new such line. All this data is stored in an array. How do I bind each input field to its respective array element, so that the array gets updated when the user edits a value?
Working example with two lines of two columns each:
import { useState} from 'react';
function App() {
var [name1, setName1] = useState('Alice');
var [score1, setScore1] = useState('100');
var [name2, setName2] = useState('Bob');
var [score2, setScore2] = useState('200');
function changeNameHandler1 (e) {
console.log(e)
setName1(e.target.value)
}
function changeScoreHandler1 (e) {
setScore1(e.target.value)
}
function changeNameHandler2 (e) {
setName2(e.target.value)
}
function changeScoreHandler2 (e) {
setScore2(e.target.value)
}
return (
<div>
<table>
<tbody>
<tr>
<td><input name="name1" id="id1" type="text" value={name1} onChange={changeNameHandler1} /></td>
<td><input name="score1" type="text" value={score1} onChange={changeScoreHandler1} /></td>
</tr>
<tr>
<td><input name="name2" type="text" value={name2} onChange={changeNameHandler2} /></td>
<td><input name="score2" type="text" value={score2} onChange={changeScoreHandler2} /></td>
</tr>
</tbody>
</table>
{name1} has a score of {score1}<br />
{name2} has a score of {score2}<br />
</div>
);
}
export default App;
How do I scale this up without having to add handler functions for hundreds of fields individually?
You can still store your fields in an object and then just add to the object when you want to add a field. Then map through the keys to display them.
Simple example:
import { useState } from 'react'
const App = () => {
const [fields, setFields ] = useState({
field_0: ''
})
const handleChange = (e) => {
setFields({
...fields,
[e.target.name]: e.target.value
})
}
const addField = () => setFields({
...fields,
['field_' + Object.keys(fields).length]: ''
})
const removeField = (key) => {
delete fields[key]
setFields({...fields})
}
return (
<div>
{Object.keys(fields).map(key => (
<div>
<input onChange={handleChange} key={key} name={key} value={fields[key]} />
<button onClick={() => removeField(key)}>Remove Field</button>
</div>
))}
<button onClick={() => addField()}>Add Field</button>
<button onClick={() => console.log(fields)}>Log fields</button>
</div>
);
};
export default App;
Here is what I think you are trying to achieve in your question:
import { useState } from 'react'
const App = () => {
const [fieldIndex, setFieldIndex] = useState(1)
const [fields, setFields ] = useState({
group_0: {
name: '',
score: ''
}
})
const handleChange = (e, key) => {
setFields({
...fields,
[key]: {
...fields[key],
[e.target.name]: e.target.value
}
})
}
const addField = () => {
setFields({
...fields,
['group_' + fieldIndex]: {
name: '',
score: ''
}
})
setFieldIndex(i => i + 1)
}
const removeField = (key) => {
delete fields[key]
setFields({...fields})
}
return (
<div>
{Object.keys(fields).map((key, index) => (
<div key={key}>
<div>Group: {index}</div>
<label>Name:</label>
<input onChange={(e) => handleChange(e, key)} name='name' value={fields[key].name} />
<label>Score: </label>
<input onChange={(e) => handleChange(e, key)} name='score' value={fields[key].score} />
<button onClick={() => removeField(key)}>Remove Field Group</button>
</div>
))}
<button onClick={() => addField()}>Add Field</button>
<button onClick={() => console.log(fields)}>Log fields</button>
</div>
);
};
export default App;
You may want to keep the index for naming in which case you can use an array. Then you would just pass the index to do your input changing. Here is an example of using an array:
import { useState } from 'react'
const App = () => {
const [fields, setFields ] = useState([
{
name: '',
score: ''
}
])
const handleChange = (e, index) => {
fields[index][e.target.name] = e.target.value
setFields([...fields])
}
const addField = () => {
setFields([
...fields,
{
name: '',
score: ''
}
])
}
const removeField = (index) => {
fields.splice(index, 1)
setFields([...fields])
}
return (
<div>
{fields.map((field, index) => (
<div key={index}>
<div>Group: {index}</div>
<label>Name:</label>
<input onChange={(e) => handleChange(e, index)} name='name' value={field.name} />
<label>Score: </label>
<input onChange={(e) => handleChange(e, index)} name='score' value={field.score} />
<button onClick={() => removeField(index)}>Remove Field Group</button>
</div>
))}
<button onClick={() => addField()}>Add Field</button>
<button onClick={() => console.log(fields)}>Log fields</button>
</div>
);
};
export default App;
have multiple solutions to this problem for example:
Solution #1
Using useRef to store value of the field
import { useRef, useCallback } from "react";
export default function App() {
const fullNameInputElement = useRef();
const emailInputElement = useRef();
const passwordInputElement = useRef();
const passwordConfirmationInputElement = useRef();
const formHandler = useCallback(
() => (event) => {
event.preventDefault();
const data = {
fullName: fullNameInputElement.current?.value,
email: emailInputElement.current?.value,
password: passwordInputElement.current?.value,
passwordConfirmation: passwordConfirmationInputElement.current?.value
};
console.log(data);
},
[]
);
return (
<form onSubmit={formHandler()}>
<label htmlFor="full_name">Full name</label>
<input
ref={fullNameInputElement}
id="full_name"
placeholder="Full name"
type="text"
/>
<label htmlFor="email">Email</label>
<input
ref={emailInputElement}
id="email"
placeholder="Email"
type="email"
/>
<label htmlFor="password">Password</label>
<input
ref={passwordInputElement}
id="password"
placeholder="Password"
type="password"
/>
<label htmlFor="password_confirmation">Password Confirmation</label>
<input
ref={passwordConfirmationInputElement}
id="password_confirmation"
placeholder="Password Confirmation"
type="password"
/>
<button type="submit">Submit</button>
</form>
);
}
or still use useState but store all values in one object
import { useState, useCallback } from "react";
const initialUserData = {
fullName: "",
email: "",
password: "",
passwordConfirmation: ""
};
export default function App() {
const [userData, setUserData] = useState(initialUserData);
const updateUserDataHandler = useCallback(
(type) => (event) => {
setUserData({ ...userData, [type]: event.target.value });
},
[userData]
);
const formHandler = useCallback(
() => (event) => {
event.preventDefault();
console.log(userData);
},
[userData]
);
return (
<form onSubmit={formHandler()}>
<label htmlFor="full_name">Full name</label>
<input
id="full_name"
placeholder="Full name"
type="text"
value={userData.fullName}
onChange={updateUserDataHandler("fullName")}
/>
<label>Email</label>
<input
id="email"
placeholder="Email"
type="email"
value={userData.email}
onChange={updateUserDataHandler("email")}
/>
<label htmlFor="password">Password</label>
<input
id="password"
placeholder="Password"
type="password"
value={userData.password}
onChange={updateUserDataHandler("password")}
/>
<label htmlFor="password_confirmation">Password Confirmation</label>
<input
id="password_confirmation"
placeholder="Password Confirmation"
type="password"
value={userData.passwordConfirmation}
onChange={updateUserDataHandler("passwordConfirmation")}
/>
<button type="submit">Submit</button>
</form>
);
}
Solution #2
Or you have multiple libraries that also provide solutions like react-form-hook https://react-hook-form.com/

react-phone-number-input code sample using http API

Just asking how to get this and put it to my API. Here's a link: https://web.5writer.com/user/signup
{
"countryCallingCode": "374",
"nationalNumber": "23131223",
"number": "+37423131223",
"country": "AM"
}
This is the body of my API
{
dial_code,
mobile,
iso_code
}
This is my code
export default function Home() {
const toast = useToast()
const router = useRouter();
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false);
const [dial_code, setDial] = useState('');
const [mobile, setMobile] = useState('');
const [iso_code, setIso] = useState('');
async function handleSubmit (e) {
e.preventDefault();
setLoading(true);
fetch(`https://web.5writer.com/user/signup`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
dial_code,
mobile,
iso_code,
}),
})
.then((res) =>
res.json().then((body) => ({
status: res.status,
body,
}))
)
.then((resp) => {
console.log(resp);
setLoading(false);
if (resp.body.status === true) {
setDial('');
setMobile('');
setIso('');
toast({
title: 'Success!',
description: resp.body.message,
status: 'success',
duration: 6000,
isClosable: true,
position: 'top',
variant: 'left-accent',
});
router.push('../AllOrders/dashboard');
}
else {
toast({
title: 'ERROR!',
description: resp.body.message,
status: 'error',
duration: 6000,
isClosable: true,
position: 'top',
variant: 'left-accent',
});
}
})
}
return (
<div>
{success && <Notification />}
<main>
<Container >
<Box
w='17.8em'
p={0}
borderRadius='5px'
mt={3}
mb={-4}
mx='auto'
pos='relative'
marginLeft='-1em'
>
{loading && (
<Progress
pos='absolute'
top='0'
left='0'
width='100%'
isIndeterminate
borderTopLeftRadius='6px'
borderTopRighRtadius='6px'
size='sm'
colorScheme='blue'
/>
)}
<form onSubmit={handleSubmit}>
<FormControl className="">
<PhoneNumber
placeholder="enter phone number"
value={dial_code}
onChange={(e) => setDial(e.target.value)}
/>
</FormControl>
<div className="form-group2 d-md-flex">
<div className="w-50 text-left">
<input type="checkbox" className="checkL"/>
<div className="remember">
I have read the <a className="terms">Terms and Condition</a>
</div>
</div>
</div>
<Button
type='submit'
mt='0'
size='sm'
colorScheme='#2CBEFF'
disabled={loading}
pos='relative'
className="lbutton"
>
Register
{/* {loading && <Spinner pos='absolute' color='red.500' />} */}
</Button>
<div className="form-group3">
<p className="text-center">Already have an account?
<Link href="/Login"><a data-toggle="tab" className="Log">Log In</a></Link></p>
</div>
</form>
</Box>
</Container>
</main>
</div>
);
}
This code is working but the problem is I only got one data using onChange. Is it possible to use 3 onChange? or is there any method to get 3 data in just one input.
Give me a piece of advice thank you.
It's still not entirely clear what your issue is, but based on the comments it seems you want a single state variable and change handler to manage 3 inputs. You generally accomplish this by associating a name attribute with each input. The name attribute is accessed via the onChange event and can update the specific nested state.
Example:
const initialState = {
country: "",
countryCallingCode: "",
number: ""
};
function App() {
const [{ country, countryCallingCode, number }, setState] = React.useState(
initialState
);
const changeHandler = (e) => {
const { name, value } = e.target; // <-- destructure from event
setState((state) => ({
...state,
[name]: value // <-- use name as dynamic key
}));
};
const submitHandler = (e) => {
e.preventDefault();
const data = {
dial_code: countryCallingCode,
number,
country
};
setState(initialState);
console.log(data);
};
return (
<div className="App">
<form onSubmit={submitHandler}>
<div>
<label>
Country Code
<input
type="text"
value={countryCallingCode}
name="countryCallingCode"
onChange={changeHandler}
/>
</label>
</div>
<div>
<label>
Number
<input
type="text"
value={number}
name="number"
onChange={changeHandler}
/>
</label>
</div>
<div>
<label>
Country
<input
type="text"
value={country}
name="country"
onChange={changeHandler}
/>
</label>
</div>
<button type="submit">Submit</button>
</form>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<App />,
rootElement
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root" />
Update
If you want to use the PhoneInput component you need to map its onChange handler to your own since it passes directly the input value to the handler.
const changeHandler = (e) => {
const { name, value } = e.target;
setState((state) => ({
...state,
[name]: value
}));
};
Here the changeHandler is expecting an onChange event object. You can pass any object you like, and so long as it has the correct shape and properties the handler can handle it.
<PhoneInput
value={number}
name="number"
onChange={(value) =>
changeHandler({
target: {
name: "number",
value
}
})
}
/>
Update 2
Ok, I think I understand what you're after now. You want just a single phone number input and then to parse the country code, country, and phone number from the single state.
Check parsePhoneNumber
There's no need for any custom onChange handlers, just update state with the PhoneInput value and when you are ready, parse the state.
const [state, setState] = React.useState(null);
const submitHandler = (e) => {
e.preventDefault();
const {
countryCallingCode: dial_code,
country: iso_code,
number: mobile
} = parsePhoneNumber(state);
const data = {
dial_code,
mobile,
iso_code
};
setState(null);
// do with data now what you need
};
...
<PhoneInput value={state} onChange={setState} />
hi that's a little dirty but you can create your state somethings like this
let [values,setValues] = useState({phoneNumber : '', dial:'', code:''});
let [inputState, setInputState] = useState('phoneNumber');
const onInputChange = (e) => {
const { target : { value } } = e;
setValues(preventValues => ({...preventValues, inputState : value}))
}
const handleSubmit = (inputStateName) => {
// do your functionality then
setInputState(inputStateName);
}

Conditionally display input field

I am working on form in react. After selecting dish type I want to conditionally display other fields.
For example if I select pizza I want to display number field. If I select soup I want to display other input field.
Here is sample of code:
const Form = () => {
const [dishes] = React.useState([
{
label: "Pizza",
value: "Pizza",
},
{ label: "Soup", value: "Soup" },
{ label: "Sandwich", value: "Sandwich" },
]);
return (
<div>
<form>
<label>Name</label>
<input type="text" required></input>
<label>Preperation Time</label>
<input type="time" step="2" required></input>
<label>Type</label>
<select>
{dishes.map((dish) => (
<option key={dish.value} value={dish.value}>
{dish.label}
</option>
))}
</select>
<button>submit</button>
</form>
</div>
);
};
export default Form;
import React, { useState } from 'react';
function App() {
const [dishes] = React.useState([
{
label: "Pizza",
value: "Pizza",
},
{ label: "Soup", value: "Soup" },
{ label: "Sandwich", value: "Sandwich" },
]);
const [type, setType] = useState([])
const handleChang = (value) => {
setType(value);
}
return (
<div>
<form>
{(type == "Pizza") && (<> <label>Name</label>
<input type="text" required></input></>)
}
{(type == "Soup") && (<> <label>Preperation Time</label>
<input type="time" step="2" required></input></>)
}
<label>Type</label>
<select onChange={(e) => handleChang(e.target.value)}>
{dishes.map((dish) => (
<option key={dish.value} value={dish.value}>
{dish.label}
</option>
))}
</select>
<button>submit</button>
</form>
</div>
);
}
export default App;
Try this (codesandbox: https://codesandbox.io/s/vigilant-kepler-5xuio?file=/src/App.js)
const [dishes] = React.useState([
{
label: "Pizza",
value: "Pizza",
field: (
<div>
<label htmlFor="pizza">Toppings</label>
<input type="number" id="pizza" />
</div>
)
},
{
label: "Soup",
value: "Soup",
field: (
<div>
<label htmlFor="soup">How soupy?</label>
<input type="range" id="soup" />
</div>
)
},
{
label: "Sandwich",
value: "Sandwich",
field: (
<div>
<label htmlFor="sandwich">Enter your ingredients</label>
<input type="text" id="sandwich" />
</div>
)
}
]);
const [selectedDish, setSelectedDish] = React.useState(dishes[0]);
const handleDishSelect = (e) => {
const dish = dishes.find((dish) => dish.value === e.target.value);
if (dish) {
setSelectedDish(dish);
}
};
return (
<div>
<form>
<label>Name</label>
<input type="text" required></input>
<label>Preperation Time</label>
<input type="time" step="2" required></input>
<label>Type</label>
<select onChange={handleDishSelect}>
{dishes.map((dish) => (
<option key={dish.value} value={dish.value}>
{dish.label}
</option>
))}
</select>
{selectedDish && selectedDish.field}
<button>submit</button>
</form>
</div>
);
So you wanna display some JSX on condition right?
you can just check the condition and select a output as if condition
<div>
{dishes.value.equals("pizza") && (<input type="number">)}
{dishes.value.equals("soup") && (<input type="text">)}
</div>
You can use Ternary operation to if else condition
<div>
{dishes.value.equals("pizza") ? (<input type="number">) : (<input type="text">)}
</div>
This is the architecture I would follow (see below). First define your menu, which I presume is not changing so should just be a plain object. Then split you code in a few components:
MenuForm - this can be your main menu form component;
MenuItem - this is a component that generates selection options for a menu item
Crete additional components to handle the specifics of each menu item, say PizzaItemMenu, SoupItemMenu, etc.
Here is a full example app in action based on your code:
const menu = {
pizza: {
type: [
{
label: 'neapolitana',
value: 'npa'
}, {
label: 'chicago',
value: 'ccg'
}, {
label: '4-cheese',
value: 'cse'
}],
number: 1,
addOn: false
},
soup: {
type: [{
label: 'carrot',
value: 'crt'
}, {
label: 'potato',
value: 'ptt'
}],
number: 1,
addOn: false
}
}
const MenuForm = () => {
const [menuItem, setMenuItem] = React.useState(false);
const handleMenuItemSelection = (e) => {
setMenuItem(e.target.value);
}
const additionalMenuItemSelections = () => {
switch (menuItem) {
case 'pizza':
return <PizzaItemMenu />
case 'soup':
return <SoupItemMenu />
default:
return false;
}
}
return (
<div>
<form>
<label>Name</label>
<input type="text" required></input>
<label>Preperation Time</label>
<input type="time" step="2" required></input>
<label>Type</label>
<select className='menu' onChange={handleMenuItemSelection} defaultValue='x'>
<option disabled value="x">Select menu item</option>
{Object.keys(menu).map((item, index) => {
return (
<option key={index} value={item}>{item}</option>
)
})}
</select>
{additionalMenuItemSelections()}
<button>submit</button>
</form>
</div>
);
};
const PizzaItemMenu = () => {
const [pizzaType, setPizzaType] = React.useState(false);
const handleSelection = (e) => {
const data = e.target.value;
setPizzaType(data);
}
return (
<div className='soup-menu'>
<p>You've selected pizza!</p>
<MenuItem menuItem='pizza' handleSelection={handleSelection} />
Additional form menu selection options for pizzas goes here
{pizzaType && <p>You've selected {pizzaType} pizza!</p>}
</div>
)
}
const SoupItemMenu = () => {
const [soupType, setSoupType] = React.useState(false);
const handleSelection = (e) => {
const data = e.target.value;
setSoupType(data);
}
return (
<div className='soup-menu'>
<p>You've selected soup!</p>
<MenuItem menuItem='soup' handleSelection={handleSelection} />
Additional form menu selection options for soups goes here
{soupType && (<p>You've selected {soupType} soup!</p>)}
</div>
)
}
const MenuItem = ({ menuItem, handleSelection }) => {
const itemOptions = menu[menuItem].type;
return (
<select id={menuItem} defaultValue='x' onChange={(e) => handleSelection(e)} >
<option disabled value="x">Select {menuItem} type</option>
{itemOptions.map((itemKey, index) => (
<option key={index} value={itemKey.value}>{itemKey.label}</option>
))}
</select>
)
}
export default MenuForm;

Resources