how to update dynamically generated form in react js - reactjs

I have a code here where I have to do update operation. I'm generating the form fields dynamically based on the result of get operation. The form fields are pre-populated. On change event on the input field in triggering an error data.map is not a function on keypress. I can change for single fields with different names. But unable to update json array state. Please help. I have attached the code snippet below.
export default class PocDetail extends React.Component {
constructor(props) {
super(props);
this.state={
isLoading:true,
editData:[],
};
}
componentDidMount(){
this.renderData();
}
renderData(){
var self = this;
const getOrgId =
window.location.href.substr(window.location.href.lastIndexOf('/') + 1);
const url = "some api";
get(url+"Organisation/"+getOrgId+"/pointOfContacts/").then(function (response) {
console.log(response.data);
self.setState({
editData:response.data,
isLoading:false
})
}).catch(function (error) {
console.log(error);
});
}
putData =(e)=>{
e.preventDefault();
}
//edit permission for input fields
inputChangedHandler = (event) => {
this.setState({ editData: { ...this.state.editData,[event.target.name]:event.target.value} });
// May be call for search result
}
//the view
render() {
const {isLoading,editData} = this.state;
if(isLoading){
return <Loader />;
}
return (
<div>
<Row style={{paddingTop:'20px',paddingBottom:'40px',marginLeft:'auto',marginRight:'auto'}}>
<Col lg="8" md="8" sm="8">
<Form id="bankForm" onSubmit={this.putData}>
<ToastContainer store={ToastStore}/>
{
editData.map(data=>{
return(<Row key={data.id}>
<Col lg="6" md="6" sm="6">
<FormGroup>
<Label className="createLabelStyle" for="title">Title</Label>
<Input className="createInputStyle" type="text" name="title" id="title" autoComplete="off" value={data.title} onChange={(event)=>this.inputChangedHandler(event)} required/>
</FormGroup>
<FormGroup>
<Label className="createLabelStyle" for="first_name">First name</Label>
<Input className="createInputStyle" type="text" name="first_name" id="first_name" value={data.first_name} onChange={(event)=>this.inputChangedHandler(event)} autoComplete="off" required/>
</FormGroup>
<FormGroup>
<Label className="createLabelStyle" for="contact_number">Contact Number</Label>
<Input className="createInputStyle" type="text" name="contact_number" id="contact_number" autoComplete="off" value={(data.contact_number==null)?"":data.contact_number} onChange={(event)=>this.inputChangedHandler(event)} required/>
</FormGroup>
</Col>
<Col lg="6" md="6" sm="6">
<FormGroup>
<Label className="createLabelStyle" for="email">Email ID</Label>
<Input className="createInputStyle" type="text" name="email" value={data.email} onChange={(event)=>this.inputChangedHandler(event)} id="email" autoComplete="off" required/>
</FormGroup>
<FormGroup>
<Label className="createLabelStyle" for="last_name">Last name</Label>
<Input className="createInputStyle" type="text" name="last_name" value={data.last_name} onChange={(event)=>this.inputChangedHandler(event)} id="last_name" autoComplete="off" required/>
</FormGroup>
</Col>
</Row>);
})
}
<Button className="createSubmitStyle">Add</Button>{' '}
<Button className="createSubmitStyle">Update</Button>
</Form>
</Col>
</Row>
</div>
);
}
}

In the renderData function variable editData is an Array that's why it is rendering your form properly but in the inputChangedHandler function you are updating editData to an Object hence the issue

Please try this snippet:
editData!=undefined &&editData.map(data=>{});

I found out the solution. Adding this code below solved the problem. I needed to add index with map to update the property value of object.
inputChangedHandler(i,event){
let data = [...this.state.editData];
data[i][event.target.name] = event.target.value;
console.log(data[i][event.target.name]);
this.setState({editData:data});
}

Related

React.js - TypeError: college.map is not a function

I am trying to access the college array but it is throwing an error saying "college .map is not a function". I want to loop over the array. But when I checked the type of college it is saying that type of(college) is an object. I have declared the college state as array. I am not getting how can I loop over the college array to display the information. Thanks in advance.
Here's my code:
import React, { useState, useContext,useEffect } from 'react'
import {
Form,
FormGroup,
Label,
Input,
Button,
Col
} from 'reactstrap'
import { GlobalContext } from '../context/GlobalState'
import { useHistory } from 'react-router-dom'
import { v4 as uuid } from 'uuid'
import axios from 'axios'
const AddUser = () => {
const { addUser } = useContext(GlobalContext)
const history = useHistory()
const [fullname, setFullName] = useState('')
const [birthdate,setBirthDate]=useState()
const [address,setAddress]=useState('')
const [gender,setGender]=useState('')
const [college,setCollege]=useState([])
const handleSubmit = () => {
const newUser = {
id: uuid(),
fullname,
birthdate,
address,
college,
gender
}
addUser(newUser)
history.push('/userslist')
}
useEffect(() => {
async function fetchData(name){
const response = await axios.get(`http://universities.hipolabs.com/search`,{
params:{name}
}
)
console.log(response.data)
setCollege({ college: response.data })
}
fetchData('Middle')
}, [])
return (
<Form onSubmit={handleSubmit}>
<FormGroup>
<Label>Name</Label>
<Input type='text' placeholder='Enter Name'
value={fullname}
onChange={(e) => setFullName(e.target.value)}
name='fullname'
/>
</FormGroup>
<FormGroup>
<Label>BirthDate</Label>
<Input type='date'
placeholder='Enter BirthDate'
value={birthdate} onChange={(e)=>setBirthDate(e.target.value)}
name='birthdate'
/>
</FormGroup>
<FormGroup>
<Label>Address</Label>
<Input type='textarea'
placeholder='Enter Address'
value={address} onChange={(e)=>setAddress(e.target.value)}
name='address' />
</FormGroup>
<FormGroup row>
<Label for="exampleSelect" sm={2}>Select College Name</Label>
<Col sm={10}>
<Input type="select" name="select" id="exampleSelect" onChange={(e)=>e.target.value}>
<option value='' disabled hidden>College List</option>
{college ?
college.map((col, index) => {
return <option value={col.name} key={index + 1}>{col.name}</option>
}):null
}
</Input>
</Col>
</FormGroup>
<FormGroup tag="fieldset">
<Label>Please Select Gender</Label>
<FormGroup>
<Label>
<Input type='radio' name='gender'
onChange={(e)=>setGender(e.target.value)}
value='Male'
checked={gender === "Male"}
/>
Male
</Label>
</FormGroup>
<FormGroup>
<Label >
<Input type='radio' name='gender'
onChange={(e)=>setGender(e.target.value)}
value='Female'
checked={gender === "Female"} />
Female
</Label>
</FormGroup>
<FormGroup>
<Label>
<Input type='radio' name='gender'
onChange={(e)=>setGender(e.target.value)}
value='Other'
checked={gender === 'Other'} />
Other
</Label>
</FormGroup>
</FormGroup>
<Button type='submit'>Submit</Button>
</Form>
)
}
export default AddUser
your line: setCollege({ college: response.data }) will replace the default array you set in state. Setters for useStates always replaces the entire state.
do setCollege([...college, {college: response.data}]) instead and it should work fine
You are setting college as an object here
setCollege({ college: response.data })
Change that to
setCollege([{ college: response.data }])
Or append like
setCollege([...college, { college: response.data }])
and that will fix it.
You are directly placing the response object in your college state. .map() is function of array, so response from your API might not be in array format. Convert it into array then you can loop through array with map().

Radio Buttons in React using Bootstrap always post same value

I am not getting an error, but the radio buttons I am writing are always sending the same value to the database, and I am not sure why or how to fix it.
UPDATE. I have attached the complete code. Hopefully this provides more detail. Everything is working but the radio buttons. Can someone shed some light as to how I can fix this?
import React from "react";
import axios from "axios";
import Form from 'react-bootstrap/Form'
import Row from 'react-bootstrap/Col'
import Button from 'react-bootstrap/Button'
import './Form.css'
class Home extends React.Component {
constructor(props) {
super(props);
this.state = { tickets: [] };
this.firstName = React.createRef();
this.lastName = React.createRef();
this.email = React.createRef();
this.category = React.createRef();
this.content = React.createRef();
this.urgency = React.createRef();
}
componentDidMount() {
this.getData();
}
getData = () => {
// Java Spring Boot uses port 8080
let url = "http://localhost:8080/tickets";
// axios.get(url).then(response => console.log(response.data));
axios.get(url).then(response => this.setState({ tickets: response.data }));
};
addTicket = () => {
let url = "http://localhost:8080/tickets";
axios.post(url, {
firstName: this.firstName.current.value,
lastName: this.lastName.current.value,
email: this.email.current.value,
category: this.category.current.value,
content: this.content.current.value,
urgency: this.urgency.current.value
}).then(response => {
// refresh the data
this.getData();
// empty the input
this.firstName.current.value = "";
this.lastName.current.value = "";
this.email.current.value = "";
this.content.current.value = "";
});
};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<Form.Group className="Input">
<Form.Control type="text" name="firstName" placeholder="First Name" ref={this.firstName} />
</Form.Group>
<Form.Group className="Input">
<Form.Control type="text" name="lastName" placeholder="Last Name" ref={this.lastName} />
</Form.Group>
<Form.Group className="Input">
<Form.Control type="text" name="email" placeholder="Email" ref={this.email} />
</Form.Group>
<br></br>
<Form.Group className="dropdown">
<Form.Label>Select a Category:</Form.Label>
<Form.Control as="select" ref={this.category}>
<option value="hardware">Hardware</option>
<option value="software">Software</option>
<option value="internet">Internet</option>
<option value="other">Other</option>
</Form.Control>
</Form.Group>
<br></br>
<Form.Group className="Issue">
<Form.Label>Please Describe Your Issue:</Form.Label>
<Form.Control as="textarea" rows="7" ref={this.content} />
</Form.Group>
<fieldset>
<Form.Group as={Row}>
<Form.Label className="radio" column sm={12}>
Select the Urgency Level:<br></br>
</Form.Label>
<Form.Check className="radioButtons"
type="radio"
label="Urgent"
name="selectedOption"
value="Urgent"
ref={this.urgency}
/>
<Form.Check className="radioButtons"
type="radio"
label="Standard"
name="selectedOption"
value="Standard"
ref={this.urgency}
/>
<Form.Check className="radioButtons"
type="radio"
label="Low Priority"
name="selectedOption"
value="Low Priority"
ref={this.urgency}
/>
</Form.Group>
</fieldset>
<Button variant="secondary" type="button" className="submit" onClick={this.addTicket}>Submit Ticket</Button>
</form>
</div>
);
}
}
export default Home;
The issue is that you are pointing this.urgency to all of your Radio components 1 by 1. Here is a brief simulation of running your code from top to bottom:
<Form.Group as={Row}>
<Form.Label className="radio" column sm={12}>
Select the Urgency Level:<br></br>
</Form.Label>
<Form.Check
value="Urgent"
ref={this.urgency} // <-- this.urgency is now pointing to this 1st component
/>
<Form.Check
value="Standard"
ref={this.urgency} // <-- this.urgency is now pointing to this 2nd component
/>
<Form.Check
value="Low Priority"
ref={this.urgency} // <-- this.urgency is now pointing to this 3rd component
/>
</Form.Group>
So the final reference of this.urgency when the code is finished running is the 3rd component. So when you access this.urgency.current.value it will always return the 3rd component's value (i.e., Low Priority)
In React, you normally use state to hold these values - use ref sparsely and only if you really have to.
Here is an example of a solution:
constructor(props) {
super(props);
this.state = {
tickets: [],
urgency: "" // state for urgency
};
<Form.Group as={Row}>
<Form.Label className="radio" column sm={12}>
Select the Urgency Level:<br></br>
</Form.Label>
<Form.Check
value="Urgent"
onChange={() => this.setState({ urgency: "Urgent" })}
/>
<Form.Check
value="Standard"
onChange={() => this.setState({ urgency: "Standard" })}
/>
<Form.Check
value="Low Priority"
onChange={() => this.setState({ urgency: "Low Priority" })}
/>
</Form.Group>
axios
.post(url, {
urgency: this.state.urgency
})
you ref three elements to the same ref. you can walk around this without changing your login and adding state by helper function. in that way you don't change behavoir of your code (is not perferct ...) but you avoid rendering forced by setState.
import React from "react"
import Form from 'react-bootstrap/Form'
import Row from 'react-bootstrap/Col'
import Button from 'react-bootstrap/Button'
class Home extends React.Component {
constructor(props) {
super(props);
this.state = { tickets: [] };
this.firstName = React.createRef();
this.lastName = React.createRef();
this.email = React.createRef();
this.category = React.createRef();
this.content = React.createRef();
this.urgency = React.createRef();
}
componentDidMount() {
}
getData = () => {
};
addTicket = () => {
console.log({
firstName: this.firstName.current.value,
lastName: this.lastName.current.value,
email: this.email.current.value,
category: this.category.current.value,
content: this.content.current.value,
urgency: this.urgency.current.value
})
};
handleCheckBoxChange(ref, event){
if(event.target.checked){
ref.current = {value: event.target.value}
}
}
render() {
return (
<div>
<form onSubmit={this.addTicket}>
<Form.Group className="Input">
<Form.Control type="text" name="firstName" placeholder="First Name" ref={this.firstName} />
</Form.Group>
<Form.Group className="Input">
<Form.Control type="text" name="lastName" placeholder="Last Name" ref={this.lastName} />
</Form.Group>
<Form.Group className="Input">
<Form.Control type="text" name="email" placeholder="Email" ref={this.email} />
</Form.Group>
<br></br>
<Form.Group className="dropdown">
<Form.Label>Select a Category:</Form.Label>
<Form.Control as="select" ref={this.category}>
<option value="hardware">Hardware</option>
<option value="software">Software</option>
<option value="internet">Internet</option>
<option value="other">Other</option>
</Form.Control>
</Form.Group>
<br></br>
<Form.Group className="Issue">
<Form.Label>Please Describe Your Issue:</Form.Label>
<Form.Control as="textarea" rows="7" ref={this.content} />
</Form.Group>
<fieldset>
<Form.Group as={Row}>
<Form.Label className="radio" column sm={12}>
Select the Urgency Level:<br></br>
</Form.Label>
<Form.Check className="radioButtons"
type="radio"
label="Urgent"
name="selectedOption"
value="Urgent"
onClick={this.handleCheckBoxChange.bind(this, this.urgency)}
/>
<Form.Check className="radioButtons"
type="radio"
label="Standard"
name="selectedOption"
value="Standard"
onClick={this.handleCheckBoxChange.bind(this, this.urgency)}
/>
<Form.Check className="radioButtons"
type="radio"
label="Low Priority"
name="selectedOption"
value="Low Priority"
onClick={this.handleCheckBoxChange.bind(this, this.urgency)}
/>
</Form.Group>
</fieldset>
<Button variant="secondary" type="button" className="submit" onClick={this.addTicket}>Submit Ticket</Button>
</form>
</div>
);
}
}
export default Home;

How to use innerRef in ReactStrap ? #TypeError: Cannot read property 'username' of undefined

I want to fetch form data from innerRef in Reactstrap. But I am getting TypeError: Cannot read property 'username' of undefined
Code
<FormGroup>
<Label htmlFor="username"> Username</Label>
<Input
innerRef={(input) => (this.username.value = input)}
type="text"
name="username"
id="username"
/>
</FormGroup>
ErrorScreenshot
You can do something like this;
For stateless function component:
const Header = () => {
let username: any;
let password: any;
let checkbox: any;
const handleLogin = (event: any) => {
console.log(
"Username" +
username?.value +
"Password" +
password?.value +
"Checkbox" +
checkbox?.value
);
event.preventDefault();
};
return (
<Form onSubmit={handleLogin}>
<FormGroup>
<Label htmlFor="username">Username</Label>
<Input
type="text"
id="username"
name="username"
innerRef={(x) => (username = x)}
/>
</FormGroup>
<FormGroup>
<Label htmlFor="password">Password</Label>
<Input
type="password"
id="password"
name="password"
innerRef={(x) => (password = x)}
/>
</FormGroup>
<FormGroup check>
<Label>Remember</Label>
<Input type="checkbox" name="remember" innerRef={(x) => (checkbox = x)} />
</FormGroup>
<Button className="bg-primary" type="submit" name="submit">
Login
</Button>
</Form>
);
};

React - Input fields not editable even after I set the state

I am trying to type on the inputs but it is not allowing me too. My state changes but it doesn't show.
I am using props to show an event OR and empty event if there is no props (no event selected).
Im sorry but Stack is telling me to add more details but I don't know what else to add, I already described my problem
class EventForm extends PureComponent {
state = {
event: this.props.selectedEvt,
query: ""
};
onFormSubmit = e => {
e.preventDefault();
this.props.addEvent(this.state.event);
};
onInputChange = evt => {
console.log(evt);
evt.persist();
let newEvt = this.state.event;
newEvt[evt.target.name] = evt.target.value;
this.setState({
event: newEvt
});
};
componentDidUpdate(prevProps) {
this.props.selectedEvt &&
this.setState({
event: this.props.selectedEvt
});
}
render() {
const { event } = this.state;
return (
<form className="card" onSubmit={this.onFormSubmit}>
<div className="form-row card-body">
<div className="form-group col-md-12">
<label hmtlfor="inputName">Event Name</label>
<input
name="title"
type="text"
className="form-control"
id="inputEventName"
onChange={this.onInputChange}
value={event.title}
/>
<label hmtlfor="inputDate">Event Date</label>
<input
name="date"
type="date"
className="form-control"
id="inputEventDate"
onChange={this.onInputChange}
value={event.date}
/>
<label hmtlfor="inputDate">Event Time</label>
<input
name="time"
type="time"
className="form-control"
id="inputEventTime"
onChange={this.onInputChange}
value={event.time}
/>
<label hmtlfor="inputAddress">Address</label>
<input
name="address"
type="text"
className="form-control"
id="autocomplete"
onChange={this.onInputChange}
value={event.address}
autoComplete="new-password"
/>
<label hmtlfor="inputHost">Hosted By</label>
<input
name="host"
type="text"
className="form-control"
id="inputHost"
onChange={this.onInputChange}
value={event.host}
/>
<label hmtlfor="inputDesc">Description</label>
<textarea
name="desc"
className="form-control"
rows="5"
id="inputDesc"
wrap="soft"
onChange={this.onInputChange}
value={event.description}
/>
<button type="submit" className="btn btn-primary mt-2">
Submit
</button>
</div>
</div>
</form>
);
}
}
export default EventForm;
Every time input value change componentDidMount run and you reset state to initial state value in componentDidUpdate.
componentDidUpdate(prevProps) {
this.props.selectedEvt &&
this.setState({
event: this.props.selectedEvt // Here is the problem
});
}
Also You mutate state when input change. And because its pureComponent it will not update.
Change onInputChange to
onInputChange = evt => {
let name = evt.target.name;
let value = evt.target.value;
let newEvent = {...this.state.event};
newEvent[name] = value
this.setState({event: newEvent});
}

React - How to handle nested forms and its value

I have to setup one form which have nested values in single form
Basically I need to send data in below format to API
Payload: {"name": "The org name", "detail": "The org detail", "attributes": {"address": {"lines":[], "city":"", "state": "", "country": "India", "zip": ""}, "contacts":[{"name": "abc", "phone": "PH"}, {"name": "x", "phone": "PH"}] }}
I used react-bootstrap for handling forms.
below are the currrent code of my form
constructor(props) {
super(props);
this.state = this.getInitialState();
}
getInitialState() {
const initialState = {
organizationForm: {
name: '',
detail: '',
type: 'org',
attributes: {
contacts: [{
name: '',
phone: ''
}],
address: {
lines: [],
city: '',
state: '',
country: '',
zip: ''
}
}
},
errors: {}
};
return initialState;
}
handleChange(e) {
const organizationForm = this.state.organizationForm;
var key = e.target.name;
var value = e.target.value;
organizationForm[key] = value;
this.setState({
organizationForm
});
}
Below are the code of form
<Col className="create-content-wrap" sm={12}>
<form className="">
<FormGroup className="custom-form-group required row">
<ControlLabel className="custom-form-control-label col-sm-3">
Name
</ControlLabel>
<FormControl
className="custom-form-control col-sm-9"
type="text"
name="name"
value={organizationForm.name}
onChange={this.handleChange.bind(this)}
/>
</FormGroup>
<FormGroup className="custom-form-group required row">
<ControlLabel className="custom-form-control-label col-sm-3">
Detail
</ControlLabel>
<FormControl
className="custom-form-control col-sm-9"
type="text"
name="detail"
componentClass="textarea"
value={organizationForm.detail}
onChange={this.handleChange.bind(this)}
/>
</FormGroup>
<FormGroup className="custom-form-group row">
<ControlLabel className="custom-form-control-label col-sm-3">
Address
</ControlLabel>
<FormControl
className="custom-form-control col-sm-9"
type="text"
name="lines"
componentClass="textarea"
value={organizationForm.lines}
onChange={this.handleAddressChange.bind(this)}
/>
</FormGroup>
<FormGroup className="custom-form-group row">
<ControlLabel className="custom-form-control-label col-sm-3">
City
</ControlLabel>
<FormControl
className="custom-form-control col-sm-9"
type="text"
name="city"
value={organizationForm.attributes.address.city}
onChange={this.handleAddressChange.bind(this)}
/>
</FormGroup>
<FormGroup className="custom-form-group row">
<ControlLabel className="custom-form-control-label col-sm-3">
State
</ControlLabel>
<FormControl
className="custom-form-control col-sm-9"
type="text"
name="state"
value={organizationForm.attributes.address.state}
onChange={this.handleAddressChange.bind(this)}
/>
</FormGroup>
<FormGroup className="custom-form-group row">
<ControlLabel className="custom-form-control-label col-sm-3">
Country
</ControlLabel>
<FormControl
className="custom-form-control col-sm-9"
type="text"
name="country"
value={organizationForm.attributes.address.country}
onChange={this.handleAddressChange.bind(this)}
/>
</FormGroup>
<FormGroup className="custom-form-group row">
<ControlLabel className="custom-form-control-label col-sm-3">
Zipcode
</ControlLabel>
<FormControl
className="custom-form-control col-sm-9"
type="number"
name="zip"
value={organizationForm.attributes.address.zip}
onChange={this.handleAddressChange.bind(this)}
/>
</FormGroup>
<FormGroup className="custom-form-group row">
<ControlLabel className="custom-form-control-label col-sm-3">
Contacts
</ControlLabel>
<FormControl
className="custom-form-control col-sm-9"
type="number"
name="contacts"
value={organizationForm.attributes.contacts}
onChange={this.handleChange.bind(this)}
/>
</FormGroup>
</form>
</Col>
I am noobie in react js world. How can i bind nested fields of address and contacts ?
You can add couple of methods to handle for address and attributes like below
Way - 1
<FormControl
className="custom-form-control col-sm-9"
type="text"
name="city"
value={organizationForm.attributes.address.city}
onChange={this.handleAddressChange(this)}
/>
handleAddressChange = (e) => {
const organizationForm = this.state.organizationForm;
let address = organizationForm.attributes.address;
var key = e.target.name;
var value = e.target.value;
address[key] = value;
organizationForm.attributes.address = address;
this.setState({
organizationForm
});
}
This way your form is loosely coupled also . So if any change happens in the child object will not affect the other one. Similarly you can add for all the nested objects like address, attribute etc.
Way - 2
You can do the same by below but you need to handle which object your modifing with in the same method .
<FormControl
className="custom-form-control col-sm-9"
type="text"
name="city"
value={organizationForm.attributes.address.city}
onChange={event => { this.handleChange(event, this.state.organizationForm.attributes.address ,'address'); }}
/>
<FormControl
className="custom-form-control col-sm-9"
type="text"
name="city"
value={organizationForm.attributes.address.city}
onChange={event => { this.handleChange(event, this.state.organizationForm.attributes.contacts ,'contacts'); }}
/>
<FormControl
className="custom-form-control col-sm-9"
type="text"
name="city"
value=onChange={event => { this.handleChange(event, this.state.organizationForm ,'organizationForm'); }}
/>
handleChange = (e , object , type) => {
const organizationForm = this.state.organizationForm;
var key = e.target.name;
var value = e.target.value;
object[key] = value;
if(type === 'address'){
organizationForm.attributes.address = object;
} else if (type === 'contacts'){
organizationForm.attributes.contacts = object;
}
this.setState({
organizationForm : organizationForm
});
}
I suggest that you keep your component state flat, just one key for each field in the form. When you submit the form, then you can format it into the shape necessary for the API.
This might not work for all cases, but it worked for me and might be helpful to anyone searching this now. I had a form that rendered different input elements, but it also rendered a button that opened up a modal component with a form unrelated to the larger form surrounding it. To solve the problem of this nested form: first, I removed the form elements in the modal (the <form>) and left just the <input> inside the component. Then, in that element, I added:
onChange = {e => setValue(e.target.value)}
After this, I made a state variable that looked like this: const [value, setValue] = useState("");. And finally, I added a button under the input with something like onClick={handleSubmit} and defined a function that submitted the form with value as the result of the form submission.
So essentially, I replaced the internal state of the nested form with React state, removed the form elements and kept the input, and then created a button that would handle my submission. That way, I bypassed having nested forms by just having an input element instead of a full form.

Resources