React form value does not pass to the database - javascript

I have tried to pass current time to the mongo dB using mongoose in react. Although current time is visible on textbox, the value does not pass to the database. If I hardcode the value, it properly pass to the database. How to fix it?
const[orderTime,setOrderTime] = useState("");
function generateTime(){
var time = new Date();
return time.toLocaleTimeString();
}
<input type="text" className="form-control" id="OrderTime" placeholder="Order Time" value={generateTime()} onChange={(event)=>{
setOrderTime(event.target.value);
}}/>

Try this.
import React, { useState, useEffect } from "react";
export default function App() {
const [orderTime, setOrderTime] = useState("");
function generateTime() {
var time = new Date();
return time.toLocaleTimeString();
}
useEffect(() => {
setOrderTime(generateTime());
}, []);
return (
<div className="App">
<input
type="text"
className="form-control"
id="OrderTime"
placeholder="Order Time"
value={orderTime}
onChange={(event) => {
setOrderTime(event.target.value);
}}
/>
</div>
);
}

Related

Inputs not rerendering in react functional component

I am trying to build a booking app using react and for some reason when the user changes the state it is not re rendering the correct amount in the UI.
If I console.log() the value of guests this is not going below 0 as wanted, however the UI is not displaying the correct amount. Any suggestions ?
import React, { useEffect, useState } from 'react';
import { Link, Route, Routes } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import HotelDetails from './hotelDetails'
import '../styles/searchBar.css';
let linkStyle = { textDecoration: "none", color: "black" };
const SearchBar = (props) => {
const navigate = useNavigate()
const todaysDate = new Date();
let tomorrow = new Date(todaysDate);
tomorrow = tomorrow.setDate(tomorrow.getDate() + 1);
const [location, setLocation] = useState('');
const [startDate, setStartDate] = useState(todaysDate); // set check in date to todays date
const [endDate, setEndDate] = useState(tomorrow); // set check out date, default tomorrow
const [guests, setGuests] = useState(0);
const [properties, setProperties] = useState([]);
// debug
console.log('check in', startDate);
console.log('check out', endDate);
console.log('todays date', todaysDate);
console.log('guests', guests);
function handleCheckInDate(e) {
setStartDate(e)
}
function handleCheckOutDate(e) {
setEndDate(e)
}
useEffect(() => {
fetch(`http://localhost:5000/hotels/${location}`).then((response) => {
response.json().then((data) => {
setProperties(data);
})
})
if (guests <= 0) {
setGuests(0);
// It does not re render in the input field
}
if (endDate <= startDate) {
alert('Please select a date after your check in date');
setEndDate(tomorrow);
}
}, [location, startDate, endDate, setEndDate, setStartDate, guests, setGuests])
return (
<>
<div className='bar'>
<h2 className='subtitle'>Find your perfect stay...</h2>
<div className='searchBar'>
<div className='field'>
<input type='text' className='input' placeholder='Where to ?' onChange={(e) => setLocation(e.target.value)} required />
</div>
<p>Check in</p>
<div className='field'>
{<input type='date' className='input' placeholder={todaysDate} onChange={(e) => /*setStartDate(e.target.value)*/ handleCheckInDate(e.target.value)} required />}
</div>
<p>Check out</p>
<div className='field'>
{<input type='date' className='input' placeholder={tomorrow} onChange={(e) => /* setEndDate(e.target.value)*/ handleCheckOutDate(e.target.value)} required />}
</div>
<div className='field'>
<input type='number' className='input' placeholder='Number of guests' onChange={(e) => setGuests(e.target.value)} required />
</div>
.....
You're setting the state to reflect the input changes, but you also need to go the other way around - you need to configure the input to reflect the state. Otherwise, the state value isn't doing anything. You need
<input
type='number'
className='input'
placeholder='Number of guests'
onChange={(e) => setGuests(e.target.value)}
value={guests}
required
/>
But a better approach would be to use .valueAsNumber so that you set a number instead of a string to state, and to take the maximum of the current value and 0, instead of putting the logic in useEffect. You might also want to account for non-integer numbers.
<input
type='number'
className='input'
placeholder='Number of guests'
onChange={(e) => {
// .valueAsNumber isn't strictly needed if calling Math.max here
setGuests(Math.max(0, e.target.valueAsNumber));
}}
value={guests}
required
/>

Use state is not updating in change event

I am building a social media app with MERN stack. The issue is that the profile picture and cover picture is not changing the state.
The API is working fine but after debugging I found that use state is not accepting the new state only in initial state i.e. null.
The handleChange functionality is working well and yet after updating resulting empty object in the formData
import React, {use State } from 'react';
import { Modal, useMantineTheme } from '#mantine/core';
import { use Dispatch, use Selector } from 'react-redux';
import { useParams } from 'react-router-dom';
import { uploadImage } from '../../actions/uploadAction';
import {updateuser} from '../../actions/userAction';
const ProfileModal = ({modalOpen,setModalOpen,data}) => {
const theme = useMantineTheme();
const {password,...other} = data;
const [formData,setFormData] = useState(other);
const [profileImage,setProfileImage] = useState(null);
const [coverImage,setCoverImage] = useState(null);
const dispatch = useDispatch();
const params = useParams();
const {user} = useSelector((state)=>state.authReducer.authData);
const handleChange = (e) =>{
setFormData({...formData, [e.target.name]:e.target.value})
console.log(formData)
}
const onImageChange = (event)=>{
if (event.target.files && event.target.files[0]) {
let image = event.target.files[0]
console.log(image)
event.target.name==="profilePicture"?setProfileImage(image):setCoverImage(image)
console.log(profileImage)
console.log(coverImage)
}
}
const handleSubmit =(e)=>{
e.preventDefault();
let userData = formData;
console.log(userData);
if(profileImage){
const data = new FormData();
const fileName = Date.now() + profileImage.name;
data.append("name",fileName);
data.append("file",profileImage);
userData.profilePicture = fileName;
console.log("profile",data)
}
try {
dispatch(uploadImage(data))
} catch (error) {
console.log(error)
}
if (coverImage) {
const data = new FormData();
const fileName = Date.now() + coverImage.name;
data.append("name",fileName);
data.append("file",coverImage);
userData.coverPicture = fileName;
}
try {
dispatch(uploadImage(data))
} catch (error) {
console.log(error)
}
dispatch(updateuser(params.id,userData))
console.log(userData)
setModalOpen(false)
}
return (
<Modal
overlayColor={theme.colorScheme === 'dark' ? theme.colors.dark[9] : theme.colors.gray[2]}
overlayOpacity={0.55}
overlayBlur={3}
size = '55%'
opened = {modalOpen}
onClose ={()=>setModalOpen(false)}>
<form className='infoForm'>
<h3>Your Info</h3>
<div>
<input type='text' className='infoInput' name='firstName'
placeholder='First Name' onChange={handleChange} value={formData.firstName} />
<input type='text' className='infoInput' name='lastName'
placeholder='Last Name' onChange={handleChange} value={formData.lastName} />
</div>
<div>
<input type='text' className='infoInput' name='worksAt'
placeholder='Work Location' onChange={handleChange} value={formData.worksAt}/>
</div>
<div>
<input type='text' className='infoInput' name='livesIn'
placeholder='Lives In' onChange={handleChange} value={formData.livesIn} />
<input type='text' className='infoInput' name='country'
placeholder='Country' onChange={handleChange} value={formData.country} />
</div>
<div>
<input type='text' className='infoInput' name='relationship' placeholder='Relationship Status' onChange={handleChange}
value={formData.relationship} />
</div>
<div>
profilePicture
<input type='file' name="profilePicture" onChange={onImageChange} alt=""/>
cover Image
<input type='file' name="coverPicture" onChange={onImageChange} alt="" />
</div>
<button className='button infoButton' onClick={handleSubmit}>Update</button>
</form>
</Modal>
);
}
export default ProfileModal
Setting the state in React acts like an async function.
Meaning that the when you set the state and put a console.log right after it, it will likely run before the state has actually finished updating.
Which is why we have useEffect, a built-in React hook that activates a callback when one of it's dependencies have changed.
Example:
useEffect(() => {
console.log(formData)
// Whatever else we want to do after the state has been updated.
}, [formData])
This console.log will run only after the state has finished changing and a render has occurred.
Note: "formData" in the example is interchangeable with whatever other state piece you're dealing with.
Check the documentation for more info about this.
Change your first import line from {use State} to {useState}...no whitespace import React, {useState } from 'react';

Axios.post keeps sending empty objects to my API

I am trying to post new information about a cow to my cow API, however, everytime i hit the submit button on my frontend, it seems to be sending an empty object rather than the name of the cow, description of the cow, and image of the cow (via url). What is causing it to send an empty object versus my desired data?
Here is the frontend code:
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import './App.css';
const baseUrl = "http://localhost:3001/api/cows"
function Display({setNameOfCow, setImageOfCow, setDescriptionOfCow, nameOfCow, imageOfCow, descriptionOfCow}) {
axios.get(baseUrl)
.then(res => res.data)
.then(res => {
setNameOfCow(res.name)
setImageOfCow(res.image)
setDescriptionOfCow(res.description)
})
return (
<div>
<p>{nameOfCow}</p>
<img src={imageOfCow}/><p>{descriptionOfCow}</p>
</div>
)
}
function Input({setNameOfCow, setImageOfCow, setDescriptionOfCow, nameOfCow, imageOfCow, descriptionOfCow}) {
function handleSubmit(e) {
e.preventDefault()
let newObject = {
name: nameOfCow,
description: descriptionOfCow,
image: imageOfCow
}
axios.post(baseUrl, newObject)
}
return (
<div>
<form>
<label htmlFor="name">name: </label>
<input type="text" id="name" onChange={(e) => {
const eTarget = e.target.value
setNameOfCow(eTarget)}}/><br></br>
<label htmlFor="description">description: </label>
<input type="text" id="description" onChange={(e) => {
const eTargetDesc = e.target.value
setDescriptionOfCow(eTargetDesc)}}/><br></br>
<label htmlFor="image">image url: </label>
<input type='text' id="image" onChange={(e) => {
const eTargetImage = e.target.value
setImageOfCow(eTargetImage)}}/><br></br>
<button type="submit" onSubmit={handleSubmit}>Add a cow!</button>
</form>
</div>
)
}
function App() {
const [nameOfCow, setNameOfCow] = useState('')
const [descriptionOfCow, setDescriptionOfCow] = useState('')
const [imageOfCow, setImageOfCow] = useState('')
return (
<div className="App">
<Input imageOfCow={imageOfCow} setNameOfCow={setNameOfCow} setDescriptionOfCow={setDescriptionOfCow} setImageOfCow={setImageOfCow} />
<Display setNameOfCow={setNameOfCow} setImageOfCow={setImageOfCow} setDescriptionOfCow={setDescriptionOfCow} nameOfCow={nameOfCow} imageOfCow={imageOfCow} descriptionOfCow={descriptionOfCow} />
</div>
);
}
export default App
and here is the image showing the empty objects being posted:
Looking into your Input component props:
function Input({setNameOfCow, setImageOfCow, setDescriptionOfCow, nameOfCow, imageOfCow, descriptionOfCow}) {...
We can see that you missing to pass this props when using this component:
<Input imageOfCow={imageOfCow} setNameOfCow={setNameOfCow} setDescriptionOfCow={setDescriptionOfCow} setImageOfCow={setImageOfCow} />
The correct way to use is something like:
<Input
imageOfCow={imageOfCow}
nameOfCow={nameOfCow}
descriptionOfCow={descriptionOfCow}
setNameOfCow={setNameOfCow}
setDescriptionOfCow={setDescriptionOfCow}
setImageOfCow={setImageOfCow}
/>
Also the correct way to prevent the form default behavior is setting the onSubmit and the handleSubmit at the form attribute (you can remove from the button):
<form onSubmit={handleSubmit}>
Otherwise a very nice change is to put your axios request inside a useEffect hook to prevent your app from making request every time it re-render.
Using something like this the app will make the request only at the first component render.
const getCow = async (baseUrl) => {
const cow = await axios.get(baseUrl);
setNameOfCow(cow.name);
setImageOfCow(cow.image);
setDescriptionOfCow(cow.description);
};
useEffect(() => {
getCow(baseUrl);
}, []);

using useRef in input to avoid re render in appication

I want to implement useRef so that the component in which my input tag is should not re-render on value change. If we use useState it will re-render the entire component on every key pressed.
This is how we usually do it but this will re-render the entire component on every change.
const [name, setName] = useState('');
return(
<input type="text" placeholder="Name" value={name} onChange={e => setName(e.target.value)} />
)
I want to do this using useRef to avoid it
const name = useRef("");
const handleName = (e) => {
name.current = e.target.value
};
return(
<input type="text" placeholder="Name" value={name.current.value} onChange={handleName} />
)
but it's not working for some reason?
Change your input tag to this (inside JSX):
<input type="text" placeholder="Name" ref={name} onChange={handleName} />
Instead of value={name.current.value} use ref={name}. It should fix the issue.
Full code :
import { useRef } from "react";
export default function App() {
const name = useRef('');
const handleName = (e) => {
name.current = e.target.value
document.getElementById('test').innerText = name.current
};
return(
<>
<input type="text" placeholder="Name" ref={name} onChange={handleName} />
<p id='test'></p>
</>
)
}
if you want to avoid rendering on change, you can just pass ref to the input element. and whenever required you can get the value from ref as used in the handleSubmit method below. Html input element will maintain its state:
const nameRef = useRef(null);
const handleSubmit = () => {
console.log(nameRef.current.value);
};
return(
<input type="text" ref={nameRef} placeholder="Name" />
)

How to access input elements from a React function

I currently have a form that is auto generated based on the amount of "Activities" a current user has. Each activity has a name and a value. My goal is to submit these values to the backend to update them. Yet I can't figure out how to reference these inputs. I was trying to read about using "ref"s, yet they come back with {current:null}
Here is the auto generated list (excuse the placeholder text)
When I inspect console here is what I find from the ref:
Here is my code:
import React, { useEffect } from "react";
import { useDispatch, useStore } from "react-redux";
import { connect } from "react-redux";
import * as actions from "../store/actions/patientSide";
export function ActivityTemplates() {
const dispatch = useDispatch();
const store = useStore();
const ref = React.createRef();
useEffect(() => {
// Update the document title using the browser API
dispatch(actions.getTodaysActivityTemplates());
}, []);
const activities = store.getState().patientSide.todays_activities;
const listedStuff = activities.map((activity) => (
<div>
{activity.activity_name}
<label for="value"> Value: </label>
<input
type="number"
id="value"
defaultValue={activity.value}
min="0"
max="10"
></input>
</div>
));
const saveActivities = () => {
var inputs = ref;
console.log(inputs);
// Insert code to run the call to the backend
};
return (
<div>
<h1> Activity Templates</h1>
<form id="form" onSubmit={saveActivities()} ref={ref}>
{listedStuff}
<input type="submit" name="save" />
</form>
</div>
);
}
export default ActivityTemplates;
I am very new to React and JS and honestly have very little idea of what I'm doing, but if someone could point me in the right direction that would be awesome!
EDIT: After sleeping on it, I've realized I've just been trying to force react into my HTML. I believe I should instead use a React Form Hook, and do it properly from the ground up.
<form onSubmit={handleOnSubmit}>
<label>User Name</label>
<input type="text" name="username" /><br/>
<label>Password</label>
<input type="password" name="password" /><br/>
<input type="submit" value="Submit" />
</form>
const handleOnSubmit = (event) => {
const formData = new FormData(event.target);
const formDetails = {};
event.preventDefault();
for (let entry of formData.entries()) {
formDetails[entry[0]] = entry[1];
};
console.log("formDetails", formDetails);
}
You are getting the input fields value from "FormData" on onSubmit.
const saveActivities = (event) => {
event.preventDefault();
const data = new FormData(event.target);
// Insert code to run the call to the backend
}
You need to store the value
const [value, setValue] = React.useState();
Then give your input a onChange={e => setValue(e.target.value)}
I would change the id though

Categories