So I've got a basic form that I'm rendering and the component needs state. I would prefer for the state to be an object instead of a list of values so I can easily call JSON.stringify(stateObject). This would enable me to easily refactor into a more re-usable HOC later where I pass the state object definition & urls as a configuration.
Anyways, what happens is that every time I modify an input, it clears out the properties which were not changed and sets the property which was changed.
See initial entry below
I add input to a different input and it removes the first input and adds the second input. Notice that Facility Name is now cleared and address is now populated.
Below is the code which is doing this
import React, { useState } from "react";
import { Form, Row, Col, Button, Container } from "react-bootstrap";
function FacilitiesCreate() {
const [Name, setName] = useState("");//not ideal
const [Latitude, setLatitude] = useState("");//not ideal
const [Longitude, setLongitude] = useState("");//not ideal
const [Description, setDescription] = useState("");//not ideal
const [AddressLineOne, setAddressLineOne] = useState("");//not ideal
const [AddressLineTwo, setAddressLineTwo] = useState("");//not ideal
const [City, setCity] = useState("");//not ideal
const [State, setState] = useState("");//not ideal
const [ZipCode, setZipCode] = useState(""); //not ideal
const [Facility, setFacility] = useState({
Name: "",
Latitude: 0,
Longitude: 0,
Description: "",
AddressLineOne: "",
AddressLineTwo: "",
City: "",
State: "",
ZipCode: "",
}); //I want to be able to JSON.stringify this for my body post call :D see handleSubmit
const createFacilityEndpoint = "https://localhost:7113/api/facilities";
const handleSubmit = async (event) => {
event.preventDefault();
let response = await fetch(createFacilityEndpoint, {
method: "POST",
headers: {
"Content-Type": "application/json;charset=utf-8",
},
body: JSON.stringify(Facility),
});
if (response.ok) {
alert("YAY!");
}
};
return (
<Container>
<h2>Create New Facility</h2>
<p>facility name: {Facility.Name}</p>
<br></br>
<p>address: {Facility.AddressLineOne}</p>
<Form onSubmit={handleSubmit}>
<Row className="mb-3">
<Col>
<Form.Label>Location Name</Form.Label>
<Form.Control
type="text"
placeholder="Location's Name"
onChange={(e) => setFacility({ Name: e.target.value })}
/>
</Col>
<Col>
<Form.Label>Latitude</Form.Label>
<Form.Control
type="float"
placeholder="Enter Latitude"
onChange={(e) => setLatitude(e.target.value)}
/>
</Col>
<Col>
<Form.Label>Longitude</Form.Label>
<Form.Control
type="float"
placeholder="Enter Longitude"
onChange={(e) => setLongitude(e.target.value)}
/>
</Col>
</Row>
<Row className="mb-3">
<Col>
<Form.Label>Description</Form.Label>
<Form.Control
as="textarea"
rows={3}
placeholder="Enter Description"
onChange={(e) => setDescription(e.target.value)}
/>
</Col>
</Row>
<Form.Group className="mb-3" controlId="formGridAddress1">
<Form.Label>Address</Form.Label>
<Form.Control
placeholder="1234 Main St"
onChange={(e) => setFacility({ AddressLineOne: e.target.value })}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="formGridAddress2">
<Form.Label>Address 2</Form.Label>
<Form.Control
placeholder="Apartment, studio, or floor"
onChange={(e) => setAddressLineTwo(e.target.value)}
/>
</Form.Group>
<Row className="mb-3">
<Form.Group as={Col} controlId="formGridCity">
<Form.Label>City</Form.Label>
<Form.Control
placeholder="Miami Beach"
onChange={(e) => setCity(e.target.value)}
/>
</Form.Group>
<Form.Group as={Col} controlId="formGridState">
<Form.Label>State</Form.Label>
<Form.Control
placeholder="FL"
onChange={(e) => setState(e.target.value)}
/>
</Form.Group>
<Form.Group as={Col} controlId="formGridZip">
<Form.Label>Zip</Form.Label>
<Form.Control
placeholder="33141"
onChange={(e) => setZipCode(e.target.value)}
/>
</Form.Group>
</Row>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</Container>
);
}
export default FacilitiesCreate;
So the above is kinda cool, except it keeps nuking the other properties in the Facility State object...
CodePudding user response:
Change the following:
(e) => setFacility({ Name: e.target.value })
to:
(e) => setFacility((oldValue) => ({ ...oldValue, Name: e.target.value }))
There is an option with useState
to provide a callback function to the set
function. This callback gets the old value of the state as parameter, so you can use it for the new state you want to set.