React Hooks update props from react-redux - reactjs

I am having an issue with props updating with Redux. I am using redux-promise-middleware, and am making a login request. My hook receives the initialState. I can see the dispatch and reducer are being correctly updated when I console.log in the mapStateToProps function. However, the props are never updated with redux.
const Login = (props) => {
const [email, updateEmail] = useState('')
const [password, updatePassword] = useState('')
const [firstName, updateFirstName] = useState('')
const [lastName, updateLastName] = useState('')
const [loginToggle, updateLoginToggle] = useState(true)
async function handleLogin() {
const loginInfo = {email, password}
await props.loginUser(loginInfo)
if (props.user.loggedIn) props.history.push('/dashboard');
}
return (
<div className="login-page">
<div className="login-register-container">
{ loginToggle ?(
<div className="login-container">
<h2>Login</h2>
<input placeholder='Email' value={email} onChange={e =>
updateEmail(e.target.value)} />
<input placeholder='Password' value={password} onChange={e => updatePassword(e.target.value)} />
<button onClick={handleLogin}> Login </button>
<p style={{cursor:"pointer"}} onClick={() => updateLoginToggle(false)}> need to register?</p>
</div>
):(
<div className="register-container">
<h2>Register</h2>
<input placeholder='First Name' value={firstName} onChange={e => updateFirstName(e.target.value)} />
<input placeholder='Last Name' value={lastName} onChange={e => updateLastName(e.target.value)} />
<input placeholder='Email' value={email} onChange={e => updateEmail(e.target.value)} />
<input placeholder='Password' value={password} onChange={e => updatePassword(e.target.value)} />
<button onClick={handleRegister}> Register </button>
<p style={{cursor:"pointer"}} onClick={() => updateLoginToggle(true)}> already have login?</p>
</div>
)}
</div>
</div>
)
}
function mapStateToProps(reduxState) {
console.log(reduxState)
return {
user: reduxState.user
}
};
export default connect(mapStateToProps, {loginUser, getUser})(Login)

Related

Fields tied to the state doesn't clear on successful form submission

I have a contact form, when the form submission is successful it should clear the form field name, email and message which is tied up to the state. The form submission is successful but form fields name, email and message doesn't clear.
For test purpose what I'm doing is passing default values to the state but this values doesn't get filled in form during initial load.
export default function Contact() {
const [name, setName] = useState('John Doe')
const [email, setEmail] = useState('me#example.com')
const [message, setMessage] = useState('Hello, this is test message.')
const onSubmit = (e) => {
e.preventDefault()
const form = {"name": name, "email": email, "message": message}
return fetch('/api/contact', {
method: 'POST',
body: JSON.stringify(form),
headers: {'Content-Type': 'application/json'}
}).then(response => {
if(response.status === 200){
setName('')
setEmail('')
setMessage('')
} else {
}
}).catch(err => err)
}
return (
<section>
<form method='post'>
<div>
<label>Name</label>
<input type="text" name="name" onChange={(e) => {setName(e.target.value)}}/>
</div>
<div>
<label>Email Address</label>
<input type="email" name="email" onChange={(e) => {setEmail(e.target.value)}}/>
</div>
<div>
<label>Message</label>
<textarea minLength={5} maxLength={2000} rows="6" name="message" onChange={(e) => {setMessage(e.target.value)}}></textarea>
</div>
<div>
<button type='submit' onClick={(e) => {onSubmit(e)}}>Send Message</button>
</div>
</form>
</section>
);
}
As User456 said, you need to add value={variable} for every <input />.
Example:
import { useState } from "react";
export default function Contact() {
const [name, setName] = useState("John Doe");
const [email, setEmail] = useState("me#example.com");
const [message, setMessage] = useState("Hello, this is test message.");
const onSubmit = (e: any) => {
e.preventDefault();
setName("");
setEmail("");
setMessage("");
};
return (
<section>
<form method="post">
<div>
<label>Name</label>
<input
type="text"
name="name"
value={name}
onChange={e => {
setName(e.target.value);
}}
/>
</div>
<div>
<label>Email Address</label>
<input
type="email"
name="email"
value={email}
onChange={e => {
setEmail(e.target.value);
}}
/>
</div>
<div>
<label>Message</label>
<textarea
minLength={5}
maxLength={2000}
name="message"
value={message}
onChange={e => {
setMessage(e.target.value);
}}></textarea>
</div>
<div>
<button
type="submit"
onClick={e => {
onSubmit(e);
}}>
Send Message
</button>
</div>
</form>
</section>
);
}

React keep focus on re-rendering input

I am building an e-commerce web app, and have run into a problem making an array of inputs. Inside DescHTML I am trying to handle onChange event, but on each update the focus on the element is lost, making it very annoying to type. Does anyone have any solution or different aproach to this whole problem? Thanks in advance.
import {useState} from 'react'
export default function UploadForm() {
const [name, setName] = useState('')
const [category, setCategory] = useState('')
const [film, setFilm] = useState('')
const [price, setPrice] = useState('')
const [descArr, setDescArr] = useState([''])
function DescHTML() {
return (
<div>
{ descArr.map((item, i) =>
<input type="text" placeholder="TEST" key={i} value={item} onChange={(e) => {
e.preventDefault()
const newArr = [...descArr]
newArr[i] = e.target.value
setDescArr(newArr)
} } /> )}
</div>
)
}
console.log(descArr)
return (
<div>
<form method="POST" action="http://localhost:3500/api/upload" encType='multipart/form-data'>
<input type="file" name="image" />
<input type="text" value={name} name="name" onChange={(e) => setName(e.target.value)} placeholder="Product name" />
<input type="text" value={category} name="category" onChange={(e) => setCategory(e.target.value)} placeholder="Category" />
<input type="text" value={film} name="film" onChange={(e) => setFilm(e.target.value)} placeholder="Film" />
<input type="text" value={price} name="price" onChange={(e) => setPrice(e.target.value)} placeholder="Price" />
<DescHTML />
<hr />
{/*<input type="submit" value="Submit" />*/}
</form>
<button onClick={() => setDescArr([...descArr, ''])}>+</button>
</div>
)
}
Move your descArr and button inside DescHTML check below code you can check more info here.
function DescHTML() {
const [descArr, setDescArr] = useState([""]);
return (
<div>
{descArr.map((item, i) => (
<input
key={i}
type="text"
placeholder="TEST"
value={item}
onChange={(e) => {
e.preventDefault();
const newArr = [...descArr];
newArr[i] = e.target.value;
setDescArr(newArr);
}}
/>
))}
<br />
<button onClick={() => setDescArr([...descArr, ""])}>+</button>
</div>
);
}
First of all - move DescHTML out of UploadForm:
function DescHTML({descArr, setDescArr}) {
return (
<div>
{descArr.map((item, i) =>
<input type="text" placeholder="TEST" key={i} value={item} onChange={(e) => {
e.preventDefault()
const newArr = [...descArr]
newArr[i] = e.target.value
setDescArr(newArr)
}}/>)}
</div>
)
}
and use it in <UploadForm> like this
<DescHTML descArr={descArr} setDescArr={setDescArr}/>
The other problem is the + button which steals the focus on click. Adding onMouseDown handler will fix this.
<button onMouseDown={(e) => e.preventDefault()} onClick={() => setDescArr([...descArr, ''])}>+</button>

How to pass state props to another component

I want to pass a state variable to another component but i don't get it what i'm doing wrong.
I have a component for radio inputs and I need to pass that taskLabel to Form component.
path is components/inputs/index.js
const TaskLabel = (props) => {
const [taskLabel, setTaskLabel] = useState('');
return (
<div label={props.taskLabel} >
<input
type='radio'
name='label'
value='urgent'
onChange={(e) => setTaskLabel(e.target.value)}
/>
<input
type='radio'
name='label'
value='not-urgent'
onChange={(e) => setTaskLabel(e.target.value)}
/>
</div>
);
};
i want to receive the taskLabel value, to use it in submitHandler function.
components/form/index.js
const Form = ({taskLabel}) => {
return (
<form onSubmit={submitHandler}>
<input
type='text'
placeholder='Text here'
className='form-input'
value={task}
onChange={(e) => {
setTask(e.target.value);
}}
/>
<TaskLabel taskLabel={taskLabel} />
</form>
)
}
This is what i tried, to pass taskLabel props from label={taskLabel}.
You need to move your state, to Form component, like this:
const [labelProp, setLabelProp] = useState("");
Your TaskLabel component should be
<TaskLabel label={{ labelProp, setLabelProp }} />
That means, you send label, as a prop to TaskLabel component.
In TaskLabel component you need to recive the prosp, by passing to component {label}.
Next, for every input use onChange={(e) => label.setLabelProp(e.target.value)}.
Edited sandbox => https://codesandbox.io/s/laughing-proskuriakova-dhi568?file=/src/components/task-label/index.js
Generally speaking, the concept is "data-down, actions-up". So if you want to pass data down to a lower-level component, you just pass a prop. If you want to update a value from a lower-level component to a higher-level component, you could pass a setter function down as a prop and call that.
Note I just call it taskLevelProp for a little more clarity. You should probably use a better name.
TaskLabel (lower level component)
/* It looks like TaskLabelProp gets passed in from something else.
Otherwise, you would use useState to get your setter function */
const TaskLabel = ({taskLabelProp, setTaskLabelProp}) => {
return (
<div label={props.taskLabel} >
<input
type='radio'
name='label'
value='urgent'
onChange={(e) => setTaskLabelProp(e.target.value)}
/>
<input
type='radio'
name='label'
value='not-urgent'
onChange={(e) => setTaskLabelProp(e.target.value)}
/>
</div>
);
};
Form (higher level component)
const Form = () => {
const [taskLabelProp, setTaskLabelProp] = useState('');
return (
<form onSubmit={submitHandler}>
<input
type='text'
placeholder='Text here'
className='form-input'
value={task}
onChange={(e) => {
setTask(e.target.value);
}}
/>
<TaskLabel taskLabel={taskLabelProp, setTaskLabelProp} />
</form>
)
}
Let me know if this answers your question.
EDIT: Made Form use useState. Based off your code, I was assuming you were using useState at the app level.
function App() {
const [task, setTask] = useState("");
const [taskLabelProp, setTaskLabelProp] = useState("");
const handleChange = (e) => {
setTaskLabelProp(e.target.value);
};
const submitHandler = (e) => {
e.preventDefault();
};
return (
<div className="App">
<form onSubmit={submitHandler}>
<input
type="text"
placeholder="Text here"
className="form-input"
value={task}
onChange={(e) => {
setTask(e.target.value);
}}
/>
<TaskLabel
onChange={handleChange}
taskLabelProp={taskLabelProp}
taskLabel="select"
/>
<button type="submit">fs</button>
</form>
</div>
);
}
export default App;
const TaskLabel = ({ taskLabel, onChange, taskLabelProp }) => {
return (
<div label={taskLabel}>
<input
type="radio"
name="label"
value="urgent"
onChange={(e) => onChange(e)}
checked={taskLabelProp === "urgent"}
/>
urgent
<input
type="radio"
name="label"
value="not-urgent"
onChange={(e) => onChange(e)}
checked={taskLabelProp === "not-urgent"}
/>
not-urgent
</div>
);
};
export default TaskLabel;

ReactJS select first option doesn't work properly

I have a react app with edit logic with select tag and options for continents and countries. In the continents it seems everything is alright but in countries I can't set a first option. First I must to select another country and then first option is available for set.
This is my code:
import React, { useState, useEffect, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import styles from './editContact.module.css';
import { urls, methods } from '../constants';
import requester from '../services/requester';
import notificationsReceiver from '../services/notificationReceiver';
const EditContact = () => {
const id = window.location.pathname.slice(14);
const navigate = useNavigate();
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [phone, setPhone] = useState('');
const [description, setDescription] = useState('');
const [categories, setCategories] = useState('');
const [areas, setAreas] = useState('');
const [event, setEvent] = useState('');
const [continentId, setContinent] = useState('');
const [countryId, setCountry] = useState('');
const [continents, setContinents] = useState([]);
const [countries, setCountries] = useState([]);
const getContact = useCallback(async () => {
const request = await requester(urls.contacts + '/' + id, methods.get);
const response = await request.json();
setName(response.name);
setEmail(response.email);
setAreas(response.areas);
setCategories(response.categories);
setDescription(response.description);
setEvent(response.event);
setPhone(response.phoneNumber);
setContinent(response.continentId);
setCountry(response.countryId);
}, [id]);
const sendToHome = () => {
navigate(urls.mainPage);
};
const editContact = async (e) => {
e.preventDefault();
await requester(urls.contacts + '/' + id, methods.put, {
name,
email,
phone,
description,
areas,
event,
categories,
continentId,
countryId
}
)
.then(() => {
navigate(urls.mainPage);
notificationsReceiver('Contact is edited successfully!');
})
.catch((e) => {
alert(e.message);
})
};
const getContinents = async () => {
const request = await requester(urls.getContinents, methods.get);
const response = await request.json();
setContinents(response);
};
const getCountries = async () => {
const request = await requester(urls.getCountries, methods.get);
const response = await request.json();
setCountries(response);
};
useEffect(() => {
getContact();
getContinents();
getCountries();
}, [getContact]);
return (
<form className={styles['edit-form']} onSubmit={editContact}>
<div className="form-group">
<label htmlFor="exampleFormControlInput1">Name</label>
<input type="text" className="form-control" id="exampleFormControlInput1" onChange={e => setName(e.target.value)} value={name} />
</div>
<label htmlFor="exampleFormControlInput1">Continent</label>
<select className="form-control" id="exampleFormControlSelect1" title="continent" name="continent" onChange={e => setContinent(e.target.value)} value={continentId}>
{continents.map(continent =>
<option key={continent.continentId} value={continent.continentId}>{continent.continentName}</option>
)}
</select>
<label htmlFor="exampleFormControlInput1">Countries</label>
<select className="form-control" id="exampleFormControlSelect1" title="country" name="country" onChange={e => setCountry(e.target.value)} value={countryId}>
{countries.filter(x => x.placeIsContainedInId === continentId).map(country =>
<option key={country.countryId} value={country.countryId}>{country.countryName}</option>
)}
</select>
<div className="form-group">
<label htmlFor="exampleFormControlInput1">eMail</label>
<input type="email" className="form-control" id="exampleFormControlInput1" onChange={e => setEmail(e.target.value)} value={email} />
</div>
<div className="form-group">
<label htmlFor="exampleFormControlInput1">Phone</label>
<input type="text" className="form-control" id="exampleFormControlInput1" onChange={e => setPhone(e.target.value)} value={phone} />
</div>
<div className="form-group">
<label htmlFor="exampleFormControlInput1">Description</label>
<input type="text" className="form-control" id="exampleFormControlInput1" onChange={e => setDescription(e.target.value)} value={description} />
</div>
<div className="form-group">
<label htmlFor="exampleFormControlInput1">Categories</label>
<input type="text" className="form-control" id="exampleFormControlInput1" onChange={e => setCategories(e.target.value)} value={categories} />
</div>
<div className="form-group">
<label htmlFor="exampleFormControlInput1">Areas</label>
<input type="text" className="form-control" id="exampleFormControlInput1" onChange={e => setAreas(e.target.value)} value={areas} />
</div>
<div className="form-group">
<label htmlFor="exampleFormControlInput1">Event</label>
<input type="text" className="form-control" id="exampleFormControlInput1" onChange={e => setEvent(e.target.value)} value={event} />
</div>
<button type='submit' className='btn btn-success mt-5' style={{ marginRight: 5 + 'px' }} name='edit'>Submit</button>
<button className='btn btn-secondary mt-5' onClick={sendToHome}>Cancel</button>
</form>
);
};
export default EditContact;
If someone knows how to resolve this problem, I'll be grateful.

How do I add input validation and multiple error messages to sign up form?

I have one input validation implemented for the username, if the username already exists the error is put on the page. I would like to implement more input validations but I'm not sure how.
I want to validate that:
no fields can be left blank, and that
the password is not numbers (i.e. 1234 is not valid, the password has to be just alphabet characters like "password")
Here is my page:
import { Link, useHistory } from 'react-router-dom'
import { useState } from 'react'
const SignUp = ({ onSignup }) => {
let history = useHistory()
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [first_name, setFirstName] = useState('')
const [last_name, setLastName] = useState('')
const [email, setEmail] = useState('')
const [admin, setAdmin] = useState(true)
const [error, setError] = useState(false)
const onSubmit = (e) => {
e.preventDefault()
// username already in use
if(!username) {
return
}
onSignup({ first_name, last_name, email, username, password, admin })
.then(() => {
history.push('/dashboard')
}).catch((err) => {
setError(true)
setUsername('')
setPassword('')
setFirstName('')
setLastName('')
setEmail('')
setAdmin(true)
})
}
return (
<div className='generalFormat'>
<div className='row justify-content-center'>
<div className='col-sm-10 col-md-6 col-lg-4'>
<div className='row'>
<h1>Sign Up</h1>
</div>
<div className='row'>
<form className='signupForm' onSubmit={onSubmit}>
{error && <p className='signupError'>This username is not available</p>}
<div>
<input
type='text'
placeholder='username'
className='form-control'
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</div>
<div>
<input
type='text'
placeholder='password'
className='form-control'
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<div>
<input
type='text'
placeholder='first name'
className='form-control'
value={first_name}
onChange={(e) => setFirstName(e.target.value)}
/>
</div>
<div>
<input
type='text'
placeholder='last name'
className='form-control'
value={last_name}
onChange={(e) => setLastName(e.target.value)}
/>
</div>
<div>
<input
type='text'
placeholder='email'
className='form-control'
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className='d-grid gap-2 mx-auto'>
<button className='btn btn-primary' type='submit'>Sign Up</button>
</div>
<Link to="/login">Already have an acount? Log In</Link>
</form>
</div>
</div>
</div>
</div>
)
}
export default SignUp
Here is a image of the error on the username

Resources