Maximum update depth exceeded with useEffect & map - javascript

I am facing this when I am trying to set form error object. Basically, I want to show the errors below each input field. In response, I am getting an array of objects how do I set to my error object?
Error - Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
import axios from "axios";
import React, { useState, useEffect, useCallback } from "react";
import { Link } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { register } from "../actions/userActions";
const Register = () => {
const [countriesList, setCountriesList] = useState("");
const [userRegistration, setUserRegistration] = useState({
firstName: "",
lastName: "",
email: "",
password: "",
fullAddress: "",
city: "",
zipCode: "",
country: "",
phone: "",
terms: true,
});
const [userRegistrationError, setUserRegistrationError] = useState({
firstNameError: "",
lastNameError: "",
emailError: "",
passwordError: "",
fullAddressError: "",
cityError: "",
zipCodeError: "",
countryError: "",
phoneError: "",
termsError: "",
});
const dispatch = useDispatch();
const userRegister = useSelector((state) => state.userRegister);
const { loading, errors, success } = userRegister;
useEffect(() => {
const countries = async () => {
try {
const { data } = await axios.get(
`https://restcountries.eu/rest/v2/all`
);
setCountriesList(data);
} catch (err) {
console.error(err);
}
};
countries();
}, []);
useEffect(() => {
const handleErrors = (errors) => {
errors.map((error) => {
if (error.param === "firstname") {
setUserRegistrationError({
...userRegistrationError,
firstNameError: error.msg,
});
}
if (error.param === "email") {
setUserRegistrationError({
...userRegistrationError,
emailError: error.msg,
});
}
return null;
});
};
if (errors) {
handleErrors(errors);
}
}, [errors, setUserRegistrationError]);
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setUserRegistration({ ...userRegistration, [name]: value });
};
const handleChkChange = (e) => {
const checked = e.target.checked;
console.log(checked);
setUserRegistration({ ...userRegistration, terms: checked });
};
const handleSubmit = (e) => {
e.preventDefault();
try {
dispatch(register());
} catch (error) {
console.error(error);
}
};
return (
<div className="form_container">
<form action="" onSubmit={handleSubmit}>
<div className="row no-gutters">
<div className="col-6 pr-1">
<div className="form-group">
<div className="form-group">
<input
type="text"
name="firstName"
className="form-control"
placeholder="First Name*"
value={userRegistration.firstName}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.firstNameError &&
userRegistrationError.firstNameError}
</p>
</div>
</div>
</div>
<div className="col-6 pr-1">
<div className="form-group">
<input
type="text"
className="form-control"
name="lastName"
placeholder="Last Name*"
value={userRegistration.lastName}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.lastNameError &&
userRegistrationError.lastNameError}
</p>
</div>
</div>
</div>
<hr />
<div className="private box">
<div className="row no-gutters">
<div className="col-6 pr-1">
<div className="form-group">
<input
type="email"
className="form-control"
name="email"
id="email_2"
placeholder="Email*"
value={userRegistration.email}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.emailError &&
userRegistrationError.emailError}
</p>
</div>
</div>
<div className="col-6 pl-1">
<div className="form-group">
<input
type="password"
className="form-control"
name="password"
id="password_in_2"
placeholder="Password*"
value={userRegistration.password}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.passwordError &&
userRegistrationError.passwordError}
</p>
</div>
</div>
<div className="col-12">
<div className="form-group">
<input
type="text"
name="fullAddress"
className="form-control"
placeholder="Full Address*"
value={userRegistration.fullAddress}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.fullAddressError &&
userRegistrationError.fullAddressError}
</p>
</div>
</div>
</div>
{/* /row */}
<div className="row no-gutters">
<div className="col-6 pr-1">
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="City*"
name="city"
value={userRegistration.city}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.cityError &&
userRegistrationError.cityError}
</p>
</div>
</div>
<div className="col-6 pl-1">
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="Postal Code*"
name="zipCode"
value={userRegistration.zipCode}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.zipCodeError &&
userRegistrationError.zipCodeError}
</p>
</div>
</div>
</div>
{/* /row */}
<div className="row no-gutters">
<div className="col-6 pr-1">
<div className="form-group">
<div className="custom-select-form">
<select
className="wide add_bottom_10 form-control"
name="country"
id="country"
value={userRegistration.country}
onChange={handleChange}
>
<option>Country*</option>
{countriesList &&
countriesList.map((country) => (
<option
key={country.alpha2Code}
value={country.alpha2Code}
>
{country.name}
</option>
))}
</select>
<p className="form-vald-error">
{userRegistrationError.countryError &&
userRegistrationError.countryError}
</p>
</div>
</div>
</div>
<div className="col-6 pl-1">
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="Telephone *"
name="phone"
value={userRegistration.phone}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.phoneError &&
userRegistrationError.phoneError}
</p>
</div>
</div>
</div>
{/* /row */}
</div>
<hr />
<div className="form-group">
<label className="container_check">
Accept <Link to="#0">Terms and conditions</Link>
<input
type="checkbox"
name="terms"
checked={userRegistration.terms}
onChange={handleChkChange}
/>
<span className="checkmark" />
<p className="form-vald-error">
{userRegistrationError.termsError &&
userRegistrationError.termsError}
</p>
</label>
</div>
<div className="text-center">
<input
type="submit"
defaultValue="Register"
className="btn_1 full-width"
/>
</div>
</form>
</div>
);
};
export default Register;

your effect depends on userRegistrationError which is an object, reference based. Each time useEffect runs,setUserRegistrationError
creates a new object reference, which leads to an infinite loop since references won't be the same as the previous one.
One approach to avoid this issue and keep the right references, is to pass a callback function to setUserRegistrationError instead than a value. This way userRegistrationError is no longer a dependency, it will be an argument to your function instead:
useEffect(() => {
const handleErrors = (errors) => {
errors.forEach((error) => {
if (error.param === "firstName") {
// here you pass a callback function instead, and userRegistrationError is no longer a dependency
// and returns the next state as expected
setUserRegistrationError(userRegistrationError => ({
...userRegistrationError,
firstNameError: error.msg,
}));
}
if (error.param === "email") {
setUserRegistrationError(userRegistrationError => ({
...userRegistrationError,
emailError: error.msg,
}));
}
});
};
if (errors) {
handleErrors(errors);
}
}, [errors, setUserRegistrationError]);

You have a problem with the second useEffect, the first time you update your state userRegistrationError, the component re-rendered and re-executed the useeffect because the dependency userRegistrationError has changed and the process gets repeated again because the state gets updated every render.
useEffect(() => {
const handleErrors = (errors) => {
errors.map((error) => {
if (error.param === "firstname") {
setUserRegistrationError({
...userRegistrationError,
firstNameError: error.msg,
});
}
if (error.param === "email") {
setUserRegistrationError({
...userRegistrationError,
emailError: error.msg,
});
}
return null;
});
};
if (errors) {
handleErrors(errors);
}
}, [errors, setUserRegistrationError ]); //replace userRegistrationError by setUserRegistrationError

Related

Why is the entry in the state deleted?

I tried to do something very simple but I do not understand why it not working for me
so i have a component that include the details about the user are logged in
and i want to request the details user and put them in the component
so I do a axios.get to my back-end i get the detail set them in the state with success put them in the component but when I refresh the page i get state is undefined
I add here the code
import axios from "axios";
import React, { useEffect, useState } from "react";
import { useParams, useNavigate } from 'react-router-dom'
import './account.css'
function Account(props) {
const [user, setUser] = useState()
const [currentPass, setCurrentPass] = useState()
const [newPass, setNewPass] = useState()
const [confirmPass, setConfirmPass] = useState()
let navigate = useNavigate();
useEffect(() => {
let userArr = []
try {
axios.create({ withCredentials: true }).get(`http://127.0.0.1:3000/users/getMe`)
.then(res => {
console.log(res.data.data.user) //object
userArr.push(res.data.data.user)
console.log(userArr)
setUser(userArr)
console.log(user)
})
} catch (error) {
console.log(error)
}
}, [])
const updatePassword = async (e) => {
e.preventDefault()
try {
const res = await axios.create({ withCredentials: true }).patch(`http://127.0.0.1:3000/users/updatePassword`, {
currentPassword: currentPass,
newPassword: newPass,
passwordConfirm: confirmPass
});
if (!res) {
return "not work"
}
console.log(res.data.data.user)
navigate("/", { replace: true });
} catch (error) {
console.log(error);
}
}
return (
<div className="account-container" >
<div className="title-container">
<p className="title">My Account</p>
</div>
<p className="sub-title">User information </p>
<form className="form-user-information">
<div className="div-form-user-information">
<label className="label-form-user-information">Username</label>
<textarea placeholder="Username..." />
</div>
<div className="div-form-user-information">
<label className="label-form-user-information">ssss</label>
<textarea placeholder={user.map(el => {
return el.email
})} />
</div>
<div className="div-form-user-information">
<label className="label-form-user-information">First name</label>
<textarea placeholder="First name..." />
</div>
<div className="div-form-user-information">
<label className="label-form-user-information">Last name</label>
<textarea placeholder="Last name..." />
</div>
</form>
<div className="buttom-line"></div>
{/* //////CONTACT INFORMATION////////// */}
<p className="sub-title-contact">CONTACT INFORMATION </p>
<form className="form-contact-information">
<div className="div-form-contact-information">
<label className="label-form-contact-information">Full Address</label>
<textarea placeholder="Full Address..." />
</div>
<div className="div-form-contact-information">
<label className="label-form-contact-information">City</label>
<textarea placeholder="City..." />
</div>
<div className="div-form-contact-information">
<label className="label-form-contact-information">Country</label>
<textarea placeholder="Country..." />
</div>
<div className="div-form-contact-information">
<label className="label-form-contact-information">Postal code</label>
<textarea placeholder="Postal code..." />
</div>
</form>
<div className="buttom-line-contact"></div>
{/* //////PASSWORD INFORMATION////////// */}
<p className="sub-title-password">UPDATE PASSWORD </p>
<form className="form-password-information">
<div className="div-form-password-information">
<label className="label-form-password-information">Current Password</label>
<textarea onChange={(e) => setCurrentPass(e.target.value)} placeholder="Current Password..." />
</div>
<div className="div-form-password-information">
<label className="label-form-password-information">New Password</label>
<textarea onChange={(e) => setNewPass(e.target.value)} placeholder="New Password..." />
</div>
<div className="div-form-password-information">
<label className="label-form-password-information">Confirm Password</label>
<textarea onChange={(e) => setConfirmPass(e.target.value)} placeholder="Confirm Password..." />
</div>
<button onClick={(e) => updatePassword(e)} className="btn-update-pass">Update password</button>
</form>
</div>
);
}
export default Account;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Based on your post and comment, the issue seems to be that you are trying to access the value of the user state property before it is populated by the async axios call.
This is a common occurrence in React, and is quite simple to solve via conditional rendering.
Example:
{user === undefined
? <></>
: <textarea placeholder={user.map(el => {
return el.email
})} />
}
Or, instead of an empty fragment, you can put a loader/spinner or any other UI you'd like, in-order to let the user know that something is loading.
If you have more places where you try to access the value of user, you can use the conditional rendering there as-well.
Alternativaly, like Matias mentioned, you can put the condition before the "main" return of the component.
This is useful if you have multiple places where you need to access the value of user and you don't want to copy this logic for all of them.
Example:
if (user === undefined) {
return <></>
}
return (
...
)
maybe the state is not filled when the app is rendered. Try waiting for the axios request by adding a little loading system:
import axios from "axios";
import React, { useEffect, useState } from "react";
import { useParams, useNavigate } from 'react-router-dom'
import './account.css'
function Account(props) {
const [user, setUser] = useState()
const [currentPass, setCurrentPass] = useState()
const [newPass, setNewPass] = useState()
const [confirmPass, setConfirmPass] = useState()
const [loading, setLoading] = useState(true) // add this
let navigate = useNavigate();
useEffect(() => {
let userArr = []
try {
axios.create({ withCredentials: true }).get(`http://127.0.0.1:3000/users/getMe`)
.then(res => {
console.log(res.data.data.user) //object
userArr.push(res.data.data.user)
console.log(userArr)
setUser(userArr)
console.log(user)
setLoading(false) // and this
})
} catch (error) {
console.log(error)
}
}, [])
const updatePassword = async (e) => {
e.preventDefault()
try {
const res = await axios.create({ withCredentials: true }).patch(`http://127.0.0.1:3000/users/updatePassword`, {
currentPassword: currentPass,
newPassword: newPass,
passwordConfirm: confirmPass
});
if (!res) {
return "not work"
}
console.log(res.data.data.user)
navigate("/", { replace: true });
} catch (error) {
console.log(error);
}
}
if(loading) return <p>loading</p> //and this...
return (
<div className="account-container" >
<div className="title-container">
<p className="title">My Account</p>
</div>
<p className="sub-title">User information </p>
<form className="form-user-information">
<div className="div-form-user-information">
<label className="label-form-user-information">Username</label>
<textarea placeholder="Username..." />
</div>
<div className="div-form-user-information">
<label className="label-form-user-information">ssss</label>
<textarea placeholder={user.map(el => {
return el.email
})} />
</div>
<div className="div-form-user-information">
<label className="label-form-user-information">First name</label>
<textarea placeholder="First name..." />
</div>
<div className="div-form-user-information">
<label className="label-form-user-information">Last name</label>
<textarea placeholder="Last name..." />
</div>
</form>
<div className="buttom-line"></div>
{/* //////CONTACT INFORMATION////////// */}
<p className="sub-title-contact">CONTACT INFORMATION </p>
<form className="form-contact-information">
<div className="div-form-contact-information">
<label className="label-form-contact-information">Full Address</label>
<textarea placeholder="Full Address..." />
</div>
<div className="div-form-contact-information">
<label className="label-form-contact-information">City</label>
<textarea placeholder="City..." />
</div>
<div className="div-form-contact-information">
<label className="label-form-contact-information">Country</label>
<textarea placeholder="Country..." />
</div>
<div className="div-form-contact-information">
<label className="label-form-contact-information">Postal code</label>
<textarea placeholder="Postal code..." />
</div>
</form>
<div className="buttom-line-contact"></div>
{/* //////PASSWORD INFORMATION////////// */}
<p className="sub-title-password">UPDATE PASSWORD </p>
<form className="form-password-information">
<div className="div-form-password-information">
<label className="label-form-password-information">Current Password</label>
<textarea onChange={(e) => setCurrentPass(e.target.value)} placeholder="Current Password..." />
</div>
<div className="div-form-password-information">
<label className="label-form-password-information">New Password</label>
<textarea onChange={(e) => setNewPass(e.target.value)} placeholder="New Password..." />
</div>
<div className="div-form-password-information">
<label className="label-form-password-information">Confirm Password</label>
<textarea onChange={(e) => setConfirmPass(e.target.value)} placeholder="Confirm Password..." />
</div>
<button onClick={(e) => updatePassword(e)} className="btn-update-pass">Update password</button>
</form>
</div>
);
}
export default Account;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Uncaught (in promise) Error: Response not successful: Received status code 400

I'm getting the following error:
Uncaught (in promise) Error: Response not successful: Received status code 400
ApolloError index.ts:58
error QueryManager.ts:316
notifySubscription module.js:137
onNotify module.js:176
error module.js:229
node_modules bundle.js:87211
notifySubscription module.js:137
onNotify module.js:176
error module.js:229
node_modules bundle.js:87253
iterateObserversSafely iteration.ts:13
error Concast.ts:186
notifySubscription module.js:137
onNotify module.js:176
error module.js:229
node_modules bundle.js:84249
promise callback*./node_modules/ bundle.js:84242
Subscription module.js:190
subscribe module.js:264
complete Concast.ts:213
node_modules bundle.js:87093
Concast Concast.ts:84
node_modules bundle.js:83385
node_modules bundle.js:82782
node_modules bundle.js:82781
step tslib.es6.js:102
verb tslib.es6.js:83
__awaiter tslib.es6.js:76
__awaiter tslib.es6.js:72
node_modules bundle.js:82740
node_modules bundle.js:81070
node_modules bundle.js:84883
onSubmit AddTicketModal.jsx:39
React 23
js index.js:7
factory react refresh:6
Webpack 3
I have 2 modals adding data to a MongoDB DB. One is customers and the other is tickets. The customer part is working, but I'm getting the error with the ticket submit. Any ideas?
Here is my AddTicketModal.jsx
import { useState } from "react";
import { FaListAlt } from "react-icons/fa";
import { useMutation, useQuery } from "#apollo/client";
import { GET_CUSTOMERS } from '../queries/customerQueries';
import { ADD_TICKET } from "../mutations/ticketMutations";
import { GET_TICKETS } from "../queries/ticketQueries";
export default function AddTicketModal() {
const [date, setDate] = useState('');
const [ticketNum, setTicketNum] = useState('');
const [customerId, setCustomerId] = useState('');
const [material, setMaterial] = useState('');
const [tareWeight, setTareWeight] = useState('');
const [grossWeight, setGrossWeight] = useState('');
const [netWeight, setNetWeight] = useState('');
const [notes, setNotes] = useState('');
const [addTicket] = useMutation(ADD_TICKET, {
variables: { date, ticketNum, customerId, material, tareWeight, grossWeight, netWeight, notes },
update(cache, { data: { addTicket} }) {
const { tickets } = cache.readQuery({ query: GET_TICKETS});
cache.writeQuery({
query: GET_TICKETS,
data: { tickets: [...tickets, addTicket] },
});
}
});
// Get Clients for select
const {loading, error, data} = useQuery(GET_CUSTOMERS);
const onSubmit = (e) => {
e.preventDefault();
if (date === "" || ticketNum === "" || customerId === "" || material === "" || tareWeight === "" || grossWeight === "" || netWeight === "" || notes === "") {
return alert("Please fill in all fields");
}
addTicket(date, ticketNum, customerId, material, tareWeight, grossWeight, netWeight, notes);
setDate("");
setTicketNum("");
setCustomerId("");
setMaterial("");
setTareWeight("");
setGrossWeight("");
setNetWeight("");
setNotes("");
};
if(loading) return null;
if(error) return "Something Went Wrong"
return (
<>
{ !loading && !error && (
<>
<button type="button"
className="btn btn-secondary"
data-bs-toggle="modal"
data-bs-target="#addTicketModal">
<div className="d-flex align-items-center">
<FaListAlt className="icon" />
<div>New Ticket</div>
</div>
</button>
{/* <!-- Modal --> */}
<div className="modal fade"
id="addTicketModal"
aria-labelledby="addTicketModalLabel"
aria-hidden="true">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title" id="addTicketModalLabel">New Ticket</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<form onSubmit={onSubmit}>
<div className="mb-1">
<label className="form-label">Date</label>
<input
type="text"
className="form-control" id="date"
value={date} onChange={ (e) => setDate(e.target.value) }
/>
</div>
<div className="mb-1">
<label className="form-label">Ticket #</label>
<input
type="text"
className="form-control" id="ticketNum"
value={ticketNum} onChange={ (e) => setTicketNum(e.target.value) }
/>
</div>
<div className="mb-1">
<label className="form-label">Customer</label>
<input
type="text"
className="form-control" id="customerId"
value={customerId} onChange={ (e) => setCustomerId(e.target.value) }
/>
</div>
<div className="mb-1">
<label className="form-label">Material</label>
<input
type="text"
className="form-control" id="material"
value={material} onChange={ (e) => setMaterial(e.target.value) }
/>
</div>
<div className="mb-1">
<label className="form-label">Tare Weight</label>
<input
type="text"
className="form-control" id="tareWeight"
value={tareWeight} onChange={ (e) => setTareWeight(e.target.value) }
/>
</div>
<div className="mb-1">
<label className="form-label">Gross Weight</label>
<input
type="text"
className="form-control" id="grossWeight"
value={grossWeight} onChange={ (e) => setGrossWeight(e.target.value) }
/>
</div>
<div className="mb-1">
<label className="form-label">Net Weight</label>
<input
type="text"
className="form-control" id="NetWeight"
value={netWeight} onChange={ (e) => setNetWeight(e.target.value) }
/>
</div>
<div className="mb-3">
<label className="form-label">Notes</label>
<textarea
className="form-control" id="notes"
value={notes} onChange={ (e) => setNotes(e.target.value) }>
</textarea>
</div>
<div className="mb-3">
<label className="form-label">Customer</label>
<select id="customerId" className="form-select"
value={customerId} onChange={(e) => setCustomerId(e.target.value)}>
<option value="">Select Customer</option>
{ data.customers.map((customer) => (
<option key={customer.id} value={customer.id}>
{customer.name}
</option>
) )}
</select>
</div>
<button type="submit"
data-bs-dismiss="modal" className="btn btn-primary">Submit
</button>
</form>
</div>
</div>
</div>
</div>
</>
)}
</>
);
}
Here is ticketMutation.js
import { gql } from '#apollo/client';
const ADD_TICKET = gql`
mutation AddTicket(
$date: Date!,
$ticketNum: String!,
$customerId: ID!,
$material: String!,
$tareWeight: Number!,
$grossWeight: Number!,
$netWeight: Number!,
$notes: String!
) {
addTicket(
date: $date
ticketNum: $TicketNum
customerId: $customerId
material: $material
tareWeight: $tareWeight
grossWeight: $grossWeight
netWeight: $netWeight
notes: $notes
) {
id
date
ticketNum
customerId {
name
email
phone
}
material
tareWeight
grossWeight
netWeight
notes
}
}
`
export { ADD_TICKET };
Any help is greatly appreciated!
-N8

Save data and image in table

I'm trying to save information in a table, which also has a field of type varbinary(max) (an image) (SQL Server)
class AddDoctor extends Component {
state = {
file: null,
name: "",
phoneNumber: "",
email: "",
status: "Active",
specialty: "",
specialities: [],
};
componentDidMount() {
const URL = "http://localhost:55317/api/TSpecialties";
ApiService.get(URL)
.then((data) => this.setState({ specialities: data }))
.catch((err) => console.log(err));
}
imgClick = () => {
const file = document.querySelector("#id-file");
file.click();
};
handleChange = (e) => {
const state = this.state;
state[e.target.name] = e.target.value;
this.setState({
...state,
});
};
handleFileChange = (event) => {
this.setState({
file: URL.createObjectURL(event.target.files[0]),
});
};
handleSubmit = (e) => {
e.preventDefault();
const URL = "http://localhost:55317/api/TDoctors/";
const DATA = {
doctorName: this.state.name,
doctorProfileImg: this.state.file,
doctorPhoneNumber: this.state.phoneNumber,
doctorEmail: this.state.email,
doctorStatus: this.state.status,
doctorSpecialtyId: Number(this.state.specialty),
};
let formData = new FormData();
formData.append("doctorProfileImg", DATA.doctorProfileImg);
formData.append("doctorName", DATA.doctorName);
formData.append("doctorEmail", DATA.doctorEmail);
formData.append("doctorPhoneNumber", DATA.doctorPhoneNumber);
formData.append("doctorStatus", DATA.doctorStatus);
formData.append("doctorSpecialtyId", DATA.doctorSpecialtyId);
const options = {
method: "POST",
body: formData
};
fetch(URL, options)
.then(res => console.log(res))
.catch(err => console.log("ERR: " + err))
};
render() {
return (
<div>
<form className="row g-3" onSubmit={this.handleSubmit}>
<div className="col-md-6">
<label htmlFor="name" className="form-label">
Name
</label>
<input
type="text"
className="form-control"
id="name"
name="name"
onChange={this.handleChange}
placeholder="Input your name"
/>
</div>
<div className="col-md-6">
<label htmlFor="email" className="form-label">
Email
</label>
<input
type="text"
onChange={this.handleChange}
name="email"
className="form-control"
id="email"
/>
</div>
<div className="col-md-6">
<label className="mb-2" htmlFor="phoneNumber">
Phone Number
</label>
<div className="input-group mb-2 mr-sm-2">
<div className="input-group-prepend">
<div className="input-group-text">+51</div>
</div>
<input
type="text"
onChange={this.handleChange}
className="form-control"
id="phoneNumber"
name="phoneNumber"
placeholder="Phone Number"
/>
</div>
</div>
<div className="col-md-12">
<label htmlFor="specialty" className="form-label">
Specialty
</label>
{/* */}
<select
id="specialty"
name="specialty"
onChange={this.handleChange}
className="form-select"
>
<option defaultValue>Choose...</option>
{this.state.specialities.map((sp) => (
<option value={sp.specialtyId}>
{sp.specialtyName}
</option>
))}
</select>
{/* */}
</div>
<div className="col-12 my-5">
<button
type="submit"
className="btn btn-outline-success w-100"
>
Save
</button>
</div>
</form>
<div className="col mx-5" style={{ minWidth: "250px" }}>
<img
src={ this.state.file}
id="img-select"
onClick={this.imgClick}
className="img-fluid img-thumbnail"
alt="doctor-img"
/>
<input
type="file"
style={{ display: "none" }}
onChange={this.handleFileChange}
id="id-file"
/>
</div>
</div>
);
}
}
Controller POST:
// POST: api/TDoctors
[HttpPost]
public async Task<IActionResult> PostTDoctor([FromBody] TDoctor tDoctor)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_context.TDoctor.Add(tDoctor);
await _context.SaveChangesAsync();
return CreatedAtAction("GetTDoctor", new { id = tDoctor.DoctorId }, tDoctor);
}
response on console developer tools when submit form:
and...
I have searched a lot of information and I cannot find the solution. I tried placing the multipart/form-data and it doesn't work either. I hope you can help me please.
Saving binary data to a SQL table is not a good practice, please use Azure Blob storage or some other storage service to store the files and just save the path of the file in the database column of a table

React Hooks useState() with Object TypeError: Cannot read property 'name' of undefined

I can't find the solution to this error in my code every time I try to type something in my input field. TypeError: Cannot read property 'name' of undefined
but I've done like the answer in the following post https://stackoverflow.com/a/57519847/16568705 still not work
Here is all code
MultiStepForm.js
import { useForm, useStep } from "react-hooks-helper";
import React from "react";
import { LaporanPolisi } from "./stepForm/LaporanPolisi";
const defaultData = {
laporanPolisi: {
nomorLp: "",
jenisKelamin: 0,
tanggalLp: "",
kerugian: 0,
uraianSingkat: "",
pasalDilanggar: [
{
undangUndang: "",
pasal: ""
}
]
},
pelapor: [],
saksi: [],
korban: [],
terlapor: [],
barangBukti: [],
tkp: {
kodeProvinsi: "",
kodeKabupaten: "",
kodeKecamatan: "",
kodeKelurahan: "",
kodeRT: "",
kodeRW: ""
}
}
const steps = [
{ id: "laporanPolisi" },
{ id: "pelapor" },
{ id: "saksi" },
{ id: "korban" },
{ id: "terlapor" },
{ id: "barangBukti" },
{ id: "tkp" },
{ id: "submit" }
]
export const MultiStepForm = () => {
const [formData, setForm] = useForm(defaultData);
const { step, navigation } = useStep({
steps,
initialStep: 0,
});
const props = { formData, setForm, navigation };
switch (step.id) {
case "laporanPolisi":
return <LaporanPolisi {...props} />;
case "pelapor":
return "Pelapor";
case "saksi":
return "Saksi";
case "korban":
return "Korban";
case "terlapor":
return "Terlapor";
case "barangBukti":
return "Barang Bukti";
case "tkp":
return "TKP";
case "submit":
return "Submit";
default:
return <LaporanPolisi {...props} />;
}
};
LaporanPolisi.js
import React from 'react';
export const LaporanPolisi = ({ formData, setForm, navigation }) => {
const {
laporanPolisi
} = formData;
const handleChange = e => {
const { name, value } = e.target;
console.log(name)
setForm(prevState => ({
...prevState,
laporanPolisi: {
...prevState.laporanPolisi,
[name]: value
}
}));
};
return (
<div className="card">
<div className="card-header">
<h4>Laporan Polisi</h4>
</div>
<div className="card-body">
<div className="row">
<div className="col-md-6">
<div className="form-group">
<label htmlFor="nomorLp">Nomor Laporan</label>
<input onChange={handleChange} id="nomorLp"
placeholder="Nomor Laporan" type="text" className="form-control" name="nomorLp" value={laporanPolisi.nomorLp} />
</div>
</div>
<div className="col-md-6">
<div className="form-group">
<label htmlFor="jenisKelamin">Jenis Kelamin</label>
<select onChange={handleChange} value={laporanPolisi.jenisKelamin} id="jenisKelamin" name="jenisKelamin" className="custom-select">
<option value={0}>Laki-Laki</option>
<option value={1}>Perempuan</option>
</select>
</div>
</div>
{/* <input placeholder="Tanggal Laporan" type="text" className="form-control" name="nomorLp" value={jenisKelamin}></input>
<input placeholder="Kerugian" type="text" className="form-control" name="nomorLp" value={nomorLp}></input>
<input placeholder="Uraian Singkat" type="text" className="form-control" name="nomorLp" value={nomorLp}></input>
<input placeholder="Nomor Laporan" type="text" className="form-control" name="nomorLp" value={nomorLp}></input> */}
</div>
</div>
<pre>
<code>
{JSON.stringify(formData.laporanPolisi)}
</code>
</pre>
</div>
)
}
error Image:
https://imgur.com/a/JC89ykW
thanks before sorry for my bad english.
All react components have to return a component, for example: ...
In your MultiStepForm.js there are only 2 cases meet this requirement.
And this is the way I dealt with input, if you want to update setForm, you can add it in hanldeChange:
export default function BasicExample({ formData, setForm, navigation }) {
const [input1, setInput1] =useState('');
const [input2, setInput2] =useState('');
const handleChange = e => {
e.preventDefault()
console.log(input1)
console.log(input2)
};
return (
<form onSubmit={handleChange}>
<div className="col-md-6">
<div className="form-group">
<label htmlFor="nomorLp">Nomor Laporan</label>
<input onChange={e => setInput1(e.target.value)} id="nomorLp"
placeholder="Nomor Laporan" type="text" className="form-control" name="nomorLp" value={input1} />
</div>
</div>
<div className="col-md-6">
<div className="form-group">
<label htmlFor="jenisKelamin">Jenis Kelamin</label>
<select onChange={e => setInput2(e.target.value)} value={input2} id="jenisKelamin" name="jenisKelamin" className="custom-select">
<option value={0}>Laki-Laki</option>
<option value={1}>Perempuan</option>
</select>
</div>
</div>
<button type="submit"> Summit</button>
</form>
);
}
Resolved
i need to define name like this
https://imgur.com/POGiQ5z
in section Nested Object at https://github.com/revelcw/react-hooks-helper
and then, this is my fullcode after change:
LaporanPolisi.js
import React from 'react';
export const LaporanPolisi = ({ formData, setForm, navigation }) => {
const {
laporanPolisi
} = formData;
const handleSubmit = e => {
e.preventDefault();
};
return (
<div className="card">
<div className="card-header">
<h4>Laporan Polisi</h4>
</div>
<div className="card-body">
<form onSubmit={handleSubmit}>
<div className="row">
<div className="col-md-6">
<div className="form-group">
<label htmlFor="nomorLp">Nomor Laporan</label>
<input onChange={setForm} id="nomorLp"
placeholder="Nomor Laporan" type="text" className="form-control" name="laporanPolisi.nomorLp" value={laporanPolisi.nomorLp} />
</div>
</div>
<div className="col-md-6">
<div className="form-group">
<label htmlFor="jenisKelamin">Jenis Kelamin</label>
<select onChange={setForm} id="jenisKelamin" name="laporanPolisi.jenisKelamin" className="custom-select" value={laporanPolisi.jenisKelamin}>
<option value={0}>Laki-Laki</option>
<option value={1}>Perempuan</option>
</select>
</div>
</div>
<div className="col-md-6">
<button className="btn btn-primary" onClick={() => navigation.previous()} type="button">Previous</button>
</div>
<div className="col-md-6">
<button className="btn btn-primary" onClick={() => navigation.next()} type="button">Next</button>
</div>
{/* <input placeholder="Tanggal Laporan" type="text" className="form-control" name="nomorLp" value={jenisKelamin}></input>
<input placeholder="Kerugian" type="text" className="form-control" name="nomorLp" value={nomorLp}></input>
<input placeholder="Uraian Singkat" type="text" className="form-control" name="nomorLp" value={nomorLp}></input>
<input placeholder="Nomor Laporan" type="text" className="form-control" name="nomorLp" value={nomorLp}></input> */}
</div>
</form>
</div>
<pre>
<code>
{JSON.stringify(laporanPolisi)}
</code>
</pre>
</div>
)
}
thanks everyone for answering my question

ReactJs: Get data from parent URL and pass it to child component

I am sending a form data from a form in reactjs. Some pre inputs from the user have to be sent altogether with the form. I get that data from the URL of the parent file and the form is in the child component.
Parent url:
http://localhost:3000/uploadlist?phmcy=2
I have to get the phmcy value from the URL. (Here the data have to be passed is '2').
parent component:
import Upload froimportm './Upload'
import axios from "axios";
import { Link, withRouter } from "react-router-dom";
import { useLocation } from 'react-router';
export default function Uploadlist() {
let phmcy = (new URLSearchParams(window.location.search)).get("phmcy")
var myphmcy = JSON.stringify(phmcy);
//const phmcyvalue = new URLSearchParams(this.props.location.search);
//const phmcy = phmcyvalue.get('phmcy')
console.log(myphmcy);
const ordersAPI= (url='https://localhost:44357/api/Orders') => {
return {
fetchAll: () => axios.get(url),
create: newRecord => axios.post(url, newRecord),
update: (id, updateRecord) => axios.put(url + id, updateRecord),
delete: id => axios.delete(url+id)
}
}
const addOrEdit = (formData, onSuccess) => {
ordersAPI().create(formData)
.then(res => {
onSuccess();
})
.catch(err => console.log(err.response.data))
}
return (
<div className="row">
<div className="jumbotron jumbotron-fluid py-4 "></div>
<div className="container text">
<h1 className="display-4"> Order Register</h1>
</div>
<div className="col-md-4 offset-3">
<Upload
addOrEdit = {addOrEdit}
myphmcy = {myphmcy}
/>
</div>
<div className="col-md-1">
<div> </div>
</div>
</div>
)
}
Child component: (This is where the form is. I have only included a part)
import React, {useState, useEffect} from 'react';
import myphmcy from './Uploadlist';
//const myphmcy = JSON.stringify(phmcy);
console.log(myphmcy);
const defaultImageSrc = '/images/7.jpg';
const initialFieldValues ={
orderId:0,
dateTime:'',
status:'',
status2:'',
pharmacyName:'',
customerName:'',
patientName:'',
patientAge:'',
address:'',
email:'',
teleNo:'',
customerId:1,
pharmacyId:myphmcy,//data obtaind from the URL have to posted as the pharmacyID when posting.
imageName:'',
imageSrc:'',
imageFile: null
}
export default function Upload(props) {
const {addOrEdit} = props
const {myphmcy} = props
const [values, setValues] = useState(initialFieldValues)
const[errors, setErrors] = useState({})
const handleInputChange= e => {
const {name, value} = e.target;
setValues({
...values,
[name]:value
})
}
const showPreview = e => {
if(e.target.files && e.target.files[0]){
let imageFile = e.target.files[0];
const reader = new FileReader();
reader.onload = x => {
setValues({
...values,
imageFile,
imageSrc : x.target.result
})
}
reader.readAsDataURL(imageFile)
}
else{
setValues({
...values,
imageFile:null,
imageSrc:''
})
}
}
const validate = () => {
let temp = {}
temp.customerName = values.customerName == "" ? false : true;
setErrors(temp)
return Object.values(temp).every(x => x == true)
}
const resetForm = () => {
setValues(initialFieldValues)
document.getElementById('image-uploader').value = null;
}
const handleFormSubmit = e => {
e.preventDefault()
if (validate()){
const formData = new FormData()
formData.append('orderId',values.orderId)
formData.append('dateTime',values.dateTime)
formData.append('status',values.status)
formData.append('status2',values.status2)
formData.append('pharmacyName',values.pharmacyName)
formData.append('customerName',values.customerName)
formData.append('patientName',values.patientName)
formData.append('patientAge',values.patientAge)
formData.append('address',values.address)
formData.append('email',values.email)
formData.append('teleNo',values.teleNo)
formData.append('customerId',values.customerId)
formData.append('pharmacyId',values.pharmacyId)
formData.append('imageName',values.imageName)
formData.append('imageFile',values.imageFile)
addOrEdit(formData, resetForm)
alert("Your file is being uploaded!")
}
}
const applyErrorClass = field => ((field in errors && errors[field] == false) ? ' invalid-field' : '')
return (
<>
<div className="container text-center ">
<p className="lead"></p>
</div>
<form autoComplete="off" noValidate onSubmit={handleFormSubmit}>
<div className="card">
<div className="card-header text-center">Place Your Order Here</div>
<img src={values.imageSrc} className="card-img-top"/>
<div className="card-body">
<div className="form-group">
<input type="file" accept="image/*" className="form-control-file" onChange={showPreview} id="image-uploader"/>
</div>
<div className="form-group">
<input type="datetime-local" className="form-control" placeholder="Date Time" name="dateTime" value={values.dateTime}
onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Enter the prescription items and qty" name="status" value={values.status} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="What are the symptoms?" name="status2" value={values.status2} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Pharmacy Name" name="pharmacyName" value={values.pharmacyName} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className={"form-control" + applyErrorClass('customerName')} placeholder="Your Name" name="customerName" value={values.customerName} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Patient Name" name="patientName" value={values.patientName} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Patient Age" name="patientAge" value={values.patientAge} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Delivery address" name="address" value={values.address} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Your Email" name="email" value={values.email} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Contact Number" name="teleNo" value={values.teleNo} onChange={ handleInputChange}/>
</div>
<div className="form-group text-center">
<button type="submit" className="btn btn-light">submit</button>
</div>
</div>
</div>
</form>
</>
)
}
This doesn't work well and I can't post the data. Can some genius help me with this?
Issue
For some reason you import the Uploadlist (the default export/import) and name it myphmcy, save this in the initial state, and then never consume the passed myphmcy prop. This pattern tends to lead to stale state as you need to also handle when the prop values update so you can synchronize the state value.
Solution
Storing passed props is anti-pattern in React, just consume the myphmcy prop directly in the handleFormSubmit submit handler. This ensure you are always using the latest myphmcy props value when submitting the form data.
const handleFormSubmit = e => {
e.preventDefault();
if (validate()) {
const formData = new FormData();
formData.append('orderId', values.orderId);
formData.append('dateTime', values.dateTime);
formData.append('status', values.status);
formData.append('status2', values.status2);
formData.append('pharmacyName', values.pharmacyName);
formData.append('customerName', values.customerName);
formData.append('patientName', values.patientName);
formData.append('patientAge', values.patientAge);
formData.append('address', values.address);
formData.append('email', values.email);
formData.append('teleNo', values.teleNo);
formData.append('customerId', values.customerId);
formData.append('pharmacyId', myphmcy) // <-- use the prop directly
formData.append('imageName', values.imageName);
formData.append('imageFile', values.imageFile);
addOrEdit(formData, resetForm) ;
alert("Your file is being uploaded!");
};
You are getting the myphmcy value from props but setting it outside of the function. So it will set only undefined to the pharmacyId. You need to assign the myphmcy value inside the fnuction.

Categories