Inputs not rerendering in react functional component - javascript

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
/>

Related

React form value does not pass to the database

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>
);
}

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';

How to update one field according to another in react?

I have two input fields for an exchange interface. The goal is to update the other according to input (based on exchange rate). User can input in either one.
The problem: if users input 5 and get 500 in the other, then they remove two 0 from 500, it won't be able to get the state update and return 0.05 in the other.
To make it easier to visualize, i have it in codesandbox. Below is the code.
import "./styles.css";
import React from "react";
export default function App() {
const rate = 100;
const [token, setToken] = React.useState();
const [eth, setEth] = React.useState();
console.log("token", token);
console.log("eth", eth);
return (
<div className="App">
<h1>1 eth = 100 token</h1>
<h2>goal: change one input, the other updates automatically</h2>
<input
placeholder="eth"
value={eth}
onChange={(e) => {
let eth_input = e.target.value;
console.log(eth_input);
setToken(eth_input * rate);
}}
/>
<input
placeholder="token"
value={token}
onChange={(e) => {
let token_input = e.target.value;
console.log(token_input);
setEth(token_input / rate);
}}
/>
</div>
);
}
The problem with your code is that your two inputs are both, at least to start with, uncontrolled inputs. And when I run your original codesandbox, there is a console message warning about this, when you edit either of the fields.
This comes about because although your inputs were taking their value from state, their change handlers were not updating that same state with the input value. You were updating the state of the other input, but not those themselves.
Adding the two highlighted lines below, one in each event handler, fixes this, and as far as I can tell makes things function as you intended:
import "./styles.css";
import React from "react";
export default function App() {
const rate = 100;
const [token, setToken] = React.useState();
const [eth, setEth] = React.useState();
console.log("token", token);
console.log("eth", eth);
return (
<div className="App">
<h1>1 eth = 100 token</h1>
<h2>goal: change one input, the other updates automatically</h2>
<input
placeholder="eth"
value={eth}
onChange={(e) => {
let eth_input = e.target.value;
console.log(eth_input);
setEth(eth_input); // <-- add this
setToken(eth_input * rate);
}}
/>
<input
placeholder="token"
value={token}
onChange={(e) => {
let token_input = e.target.value;
console.log(token_input);
setToken(token_input); // <-- and this
setEth(token_input / rate);
}}
/>
</div>
):
}
<input
placeholder="eth"
value={eth}
onChange={(e) => {
let eth_input = e.target.value;
console.log(eth_input);
setEth(eth_input)
setToken(eth_input * rate);
}}
/>
<input
placeholder="token"
value={token}
onChange={(e) => {
let token_input = e.target.value;
console.log(token_input);
setToken(token_input)
setEth(token_input / rate);
}}
/>

Why is this component function returning null in React JS?

So I am following the tutorial "React JS Crash Course 2021" by Brad Traversy and am setting up a function that adds a task to the main app.
I keep getting this error :
Error: AddTask(...): Nothing was returned from render.
This usually means a return statement is missing. Or, to render nothing, return null.
I don't know why this error is coming or what it means, so If someone could help me understand it and what part of the code is leading to it that would be appreciated
the code:
AddTask.js
import { useState } from 'react'
const AddTask = () =>{
const [text, setText] =useState('')
const [day, setDay] =useState('')
const [reminder, setReminder] =useState('false')
const onSubmit = (e) => {e.preventDefault()
if (!text){
alert('Please enter task text')
return
}
}
return (
<form className="add-form">
<div className="form-control">
<label>Task</label>
<input type="text" placeholder="Add Task"
value={text} onChange ={
(e) => setText(e.target.value)
}/>
</div>
<div className="form-control">
<label>Day and time</label>
<input type="text" placeholder="Add day and time"
value={day} onChange ={
(e) => setDay(e.target.value)
}/>
</div>
<div className="form-control form-control-check">
<label>Set Reminder</label>
<input type="checkbox"
value={reminder} onChange ={
(e) => setReminder(e.currentTarget.checked)
}/>
</div>
<input type ="submit" value ="save task" className="btn btn-block"/>
</form>
);
}
export default AddTask
Main App
import Header from "./components/Header";
import Tasks from "./components/Tasks";
import AddTask from "./components/AddTask";
import { useState } from 'react'
function App() {
const [tasks, setTasks] = useState ([{id:1,
text: 'Doctors Appointment',
day:'Feb 5 3:30 pm',
reminder: true,
},
{id:2,
text: 'Meeting at School',
day:'Feb 9 2:30 pm',
reminder: true,
},
{id:3,
text: 'Groceries',
day:'Feb 10 11:30 am',
reminder: false,
}]
)
//
const AddTask =(task) =>{
console.log(task)
}
// delete
const deleteTask = (id) =>{
setTasks(tasks.filter((task) => task.id !==id))
}
// Toggle Reminder
const toggleReminder = (id)=>{
setTasks(tasks.map((task)=>task.id===id ? {...task, reminder:!task.reminder}:task))
console.log(tasks)
}
return (
<div className="container">
<Header />
<AddTask onAdd={AddTask}/>
{tasks.length > 0 ? <Tasks tasks={tasks} onDelete ={deleteTask} onToggle ={toggleReminder}/>:'no tasks to show'}
</div>
);
}
export default App;
The problem is that you have declared a function called AddTask in App component, which overwrites the component AddTask from the scope
Change its name to a lower case value and it will work
const addTask =(task) =>{
console.log(task)
}
P.S. Javascript does automatic semicolon insertion and sometimes it can sometimes lead to unexpected results. Make sure you add semicolon after every statement to be safe

Datepicker Date is not changing on event handler

I am using material-UI datepicker which i followed the procedure but on event handler the date is not changing but the initial value is working fine which i give in useState. I want my datepicker to work smooth when i want to select my desire date. The example of Datepicker is also in the link
https://material-ui.com/components/pickers/#date-time-pickers
https://codesandbox.io/s/z9k3z
import {
KeyboardDatePicker,
MuiPickersUtilsProvider,
} from "#material-ui/pickers";
import DateFnsUtils from "#date-io/date-fns";
import React, { useState } from "react";
function AddCar() {
const [date, setDate] = useState(new Date());
const addCar = (e) => {
e.preventDefault();
console.log(date.toLocaleDateString());
setDate(new Date());
};
return (
<div className="addCar">
<div>
<form className="addCar__form" onSubmit={addCar}>
{/* Date */}
<div className="addCar__mainForm row ">
<div className="col-lg-3 col-md-6 col-sm-12 my-2">
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
disableToolbar
variant="inline"
format="MM-dd-yyyy"
margin="normal"
label="Select Date"
value={date}
onChange={(e) => setDate(date)}
KeyboardButtonProps={{
"aria-label": "change date",
}}
/>
</MuiPickersUtilsProvider>
</div>
</div>
<button type="submit" className="btn btn-success">
ADD CAR
</button>
</form>
</div>
</div>
);
}
export default AddCar;
You keep setting the same date from state.
const [date, setDate] = useState(new Date());
// ...
onChange={(e) => setDate(date)}
It should be:
onChange={(e) => setDate(e)}
The first parameter in DatePicker's onChange callback is the new date you've just input.
change this line
onChange={(e) => setDate(date)}
to
onChange={setDate}
Codesandbox: https://codesandbox.io/s/material-demo-forked-siueb?file=/addCar.js:939-957
You need to set the value like
onChange={(e) => setDate(e)}
Also, You don't need to set the state like this:
const [date, setDate] = useState(new Date());

Categories