i have problem with writing Page in react js? - reactjs

I can't type in the fields for a page Login on React js and mdbootstrap and css
this is the problem please my developper Help me solve this problem I have suffered with it a lot What is the solution please help me with this problem
What is the root of this problem please fix my code
This is the problem code
import React, { useState } from 'react';
export default function App() {
const [iconsActive, setIconsActive] = useState('pill1');
const handleIconsClick = (value: string) => {
if (value === iconsActive) {
return;
}
setIconsActive(value);
};
const [values, setValues] = useState({
email: '',
password: '',
});
const [submitted, setSubmitted] = useState(false);
const [showSuccess, setShowSuccess] = useState(false);
const handleInputChange = (event) => {
event.persist();
setValues((values) => ({
...values,
[event.target.email]: event.target.value,
}));
};
const isFormValid = () => {
if (!values.email || !values.password) {
return false;
} else {
return true;
}
};
const handleSubmit = (e) => {
e.preventDefault();
setSubmitted(true);
if (isFormValid()) {
setShowSuccess(true);
}
};
return (
<div
className='text-center'
id='formm'
class='register-form'
onSubmit={handleSubmit}
>
{showSuccess && (
<div class='success-message'>Success! Thank you for registering</div>
)}
<MDBTabs pills justify className='mb-3'>
<MDBCol>
<MDBTabsItem>
<MDBTabsLink
onClick={() => handleIconsClick('pill1')}
active={iconsActive === 'pill1'}
>
<MDBIcon className='me-2' />
Login
</MDBTabsLink>
</MDBTabsItem>
</MDBCol>
<MDBTabsItem>
<MDBTabsLink
onClick={() => handleIconsClick('pill2')}
active={iconsActive === 'pill2'}
>
<MDBIcon className='me-2' />
Register
</MDBTabsLink>
</MDBTabsItem>
</MDBTabs>
<MDBTabsContent>
<MDBTabsPane show={iconsActive === 'pill1'}>
<MDBInput
className='mb-4'
type='email'
id='form7Example1'
label='Email address'
disabled={showSuccess}
value={values.email}
onChange={handleInputChange}
/>
{submitted && !values.email && (
<span id='email-error'>Please enter a email</span>
)}
<MDBInput
className='mb-4'
type='password'
id='form7Example2'
label='Password'
disabled={showSuccess}
value={values.password}
onChange={handleInputChange}
/>
{submitted && !values.password && (
<span id='password-error'>Please enter a last name</span>
)}
<MDBBtn type='submit' className='mb-4' block disabled={showSuccess}>
Sign in
</MDBBtn>

Your problem is here:
setValues((values) => ({
...values,
[event.target.email]: event.target.value,
}));
You are setting value to the wrong keys.
I would suggest you to create two states and separate handlers for every input OR you can do the following:
const handleInputChange = (type) => ({target}) => {
setValues((values) => ({
...values,
[type]: target.value,
}));
};
<MDBInput
value={values.email}
onChange={handleInputChange("email")}
/>
<MDBInput
value={values.password}
onChange={handleInputChange("password")}
/>

Related

After editing data, redux cannot read id

i have a problem.
I use a form to edit my data, then when i want to see edited data, i get an ×
TypeError: Cannot read properties of undefined (reading 'id')
Pointing at my
{users &&
users.map((user) => {
return (
<div key={user.id}>
<Link to={`users/${user.id}`}> {user.name} </Link>
</div>
);
})}
Which is used to display data.
After refreshing the site (F5) it works, so i assume that the redux has problem with reading edited data for the first time, altough it do work with adding new data. anyone know what i can do?
My UserEditForm:
const UserEditForm = () => {
let { id } = useParams();
const { user } = useSelector((state) => state.user);
const [state, setState] = useState({
name: "",
birthday: "",
img: "",
});
const [error, setError] = useState("");
console.log(id);
let history = useHistory();
let dispatch = useDispatch();
const { name, birthday, img } = state;
useEffect(() => {
dispatch(getSingleUser(id));
}, []);
useEffect(() => {
if (user) {
setState({ ...user });
}
}, [user]);
const handleInputChange = (e) => {
let { name, value } = e.target;
setState({ ...state, [name]: value });
};
const handleSubmit = (e) => {
dispatch(updateUser(state, id));
history.push("/");
setError("");
};
return (
<div>
<Button
style={{ width: "100px", marginTop: "20px" }}
variant="contained"
color="secondary"
onClick={() => history.push("/")}
>
Go Back
</Button>
<h2>Edit User</h2>
{error && <h3 style={{ color: "red" }}>{error}</h3>}
<form noValidate autoComplete="off" onSubmit={handleSubmit}>
<TextField
id="standard-basic"
label="Name"
value={name || ""}
name="name"
type="text"
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
label="birthday"
name="birthday"
value={birthday || ""}
type="birthday"
onChange={handleInputChange}
/>
<br />
<TextField
id="standard-basic"
label="img"
value={img || ""}
name="img"
type="number"
onChange={handleInputChange}
/>
<Button
style={{ width: "100px" }}
variant="contained"
color="primary"
type="submit"
onChange={handleInputChange}
>
Update
</Button>
</form>
</div>
);
};
export default UserEditForm;
My UserList component:
const UserList = ({ users, history }) => {
const dispatch = useDispatch();
const fetchUsers = async () => {
const response = await axios
.get("http://localhost:3000/characters")
.catch((err) => {
console.log("Err: ", err);
});
dispatch(setUsers(response.data));
};
useEffect(() => {
fetchUsers();
}, []);
console.log(users);
return (
<div>
<button onClick={() => history.goBack()}>...back</button>
<li>
<Link to="/user/add">Add Users</Link>
</li>
{users &&
users.map((user) => {
return (
<div key={user.id}>
<Link to={`users/${user.id}`}> {user.name} </Link>
</div>
);
})}
</div>
);
};
const mapStateToProps = (state) => {
return {
users: state.allUsers.users,
};
};
export default connect(mapStateToProps, null)(UserList);

How to validate email and password using react hooks?

I am getting state values while clicking submit button but I am unable to do the validation for my login form and how to display the error messages below the input field when I enter my input wrong or empty. please give me a solution to this.Thanks in advance.
const Login = () => {
const [state, setState] = useState({
email: "",
password: ""
});
const handleChange = (e) => {
const {id, value} = e.target
setState(prevState => ({
...prevState,
[id]: value
}))
}
const handleSubmitClick = (e) => {
e.preventDefault();
console.log("Authenticated",state);
}
return(
<>
<div className="container">
<div className="title">
<form onSubmit={handleSubmitClick}>
<div className="form-group">
<input
type="email"
className="email"
placeholder="Email"
value={state.email}
onChange={handleChange}/>
</div>
<div className="form-group">
<input
type="password"
className="password"
placeholder="Password"
value={state.password}
onChange={handleChange}/>
</div>
<button type="submit" className="button">Enter</button>
</form>
</div>
</div>
</>
)
}
export default Login;
If you want to perform client-side validation, you can create hook like this:
const useEmailValidation = (email) => {
const isEmailValid = /#/.test(email); // use any validator you want
return isEmailValid;
};
And then you can use this hook in your form component:
...
const isEmailValid = useEmailValidation(state.email);
const isPasswordValid = usePasswordValidation(state.password);
const isFormValid = isEmailValid && isPasswordValid;
return (
...
<input
className={classNames({ 'invalid': !isEmailValid })}
type="email"
value={state.email}
onChange={handleChange}
/>
{!isEmailValid && 'Some error message'}
<button type="submit" disabled={!isFormValid} className="button">Enter</button>
...
);
...
Your validator hook can return validation message instead of boolean, like:
const useEmailValidation = (email) => {
if (!email || email.length === 0) {
return 'Email cannot be empty';
}
const isEmailValid = /#/.test(email); // use any validator you want
if (!isEmailValid) {
return 'Invalid email provided';
}
return null;
};
Also it is a good practice to show validation message only after field was focused before and after user tried to submit the form.
Formik is a great plugin that will help you perform form validation. The examples are also quite clear.
Or you could do something like this:
const Login = () => {
const [error, setError] = useState(null);
const [state, setState] = useState({
email: '',
password: '',
});
const validateEmail = (email) => {
const re =
/^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
};
const handleChange = (e) => {
const { id, value } = e.target;
setState((prevState) => ({
...prevState,
[id]: value,
}));
};
const handleSubmitClick = (e) => {
e.preventDefault();
if (!validateEmail(state.email)) {
setError('Invalid Email');
}
if (state.password.length < 8) {
setError('Password must be at least 8 chars long');
}
if (!error) {
// No errors.
}
};
return (
<>
<div className='container'>
<div className='title'>
{error && <div style={{ color: 'red' }}>{error}</div>}
<form onSubmit={handleSubmitClick}>
<div className='form-group'>
<input
type='email'
className='email'
placeholder='Email'
value={state.email}
onChange={handleChange}
/>
</div>
<div className='form-group'>
<input
type='password'
className='password'
placeholder='Password'
value={state.password}
onChange={handleChange}
/>
</div>
<button type='submit' className='button'>
Enter
</button>
</form>
</div>
</div>
</>
);
};
export default Login;
For an empty validation you can check it preventing the submit if the field is empty, like
const handleSubmitClick = (e) => {
e.preventDefault();
if(email.trim() === '' || password.trim() === ''){
//Add a h1 or section with the error message
}else{
console.log("Authenticated",state);
}
}
As long as the email field type is equal to email, which is your case, the browser should give an alert if the string is not an email. ("user#example.com")

How can I show the updated state?

When I'll click submit, it will save in the firestore, however, I still need to reload the page to update the state. How can I code it in a way that once I'll click submit, it will immediately reflect on the screen without reloading it?
const Account = () => {
const [displayName, setdisplayName] = useState(currentUser.displayName);
const [address, setAddress] = useState(currentUser.address);
const handleSubmit = async (event) => {
event.preventDefault();
try {
const userRef = firestore.collection("users").doc(currentUser.id);
const res = userRef.set(
{
displayName,
address,
},
{ merge: true }
);
} catch (err) {
console.log(err);
}
};
return (
<div>
<form onSubmit={handleSubmit}>
<TextField
placeholder={currentUser.displayName}
value={displayName}
color="secondary"
required
onChange={(e) => setdisplayName(e.target.value)}
/>
<TextField
type="text"
placeholder={currentUser.address}
value={address}
onChange={(e) => setAddress(e.target.value)}
required
/>
<Button type="submit">Submit</Button>
</form>
</div>
);
};
export default MyAccount;
You can use 1 flag to mark when it submit,use useState update value of flag and page will change.
const Account = () => {
const [displayName, setdisplayName] = useState(currentUser.displayName);
const [address, setAddress] = useState(currentUser.address);
const [flag,setFlag] = useState(false);
const handleSubmit = async (event) => {
event.preventDefault();
try {
const userRef = firestore.collection("users").doc(currentUser.id);
const res = userRef.set(
{
displayName,
address,
},
{ merge: true }
);
setFlag(true);
} catch (err) {
console.log(err);
}
};
return (
<div>
<form onSubmit={handleSubmit}>
<TextField
placeholder={currentUser.displayName}
value={displayName}
color="secondary"
required
onChange={(e) => setdisplayName(e.target.value)}
/>
<TextField
type="text"
placeholder={currentUser.address}
value={address}
onChange={(e) => setAddress(e.target.value)}
required
/>
<Button type="submit">Submit</Button>
</form>
</div>
);
};
export default MyAccount;

Page not re-rendering after hook state update

The page renders the input correctly, however errors only seem to appear on the second render even though they are displayed is useForm state on the first render.
So for the password field I enter a single character and the state of useForm changes to {password: "Must be at.....} but the screen does not update to display errors.password until I enter in another character.
// nodejs library that concatenates classes
// reactstrap components
import {
Button,
Card,
CardBody,
CardHeader,
Col,
Container,
Form,
FormFeedback,
FormGroup,
Input,
Row
} from "reactstrap";
import {register} from "apiCalls/AuthRequests";
import useForm from "hooks/AuthHooks";
import {registerFormValidation} from "components/validation/AuthFormValidation";
function RegisterForm(props) {
const [loading, setLoading] = useState(false);
const {values, handleChange, handleSubmit, errors, setErrors} = useForm(submit, registerFormValidation);
const emailRef = useRef(null);
const passwordRef = useRef(null);
const accessCodeRef = useRef(null);
async function submit() {
setLoading(true);
const response = await register(values.email, values.password, values.accessCode);
if (response.ok) {
} else if (response.status === 422) {
if ("access_code" in response.data) {
accessCodeRef.current.focus();
setErrors({accessCode: response.data.access_code});
}
if ("email" in response.data) {
setErrors({email: response.data.email});
emailRef.current.focus();
}
if ("password" in response.data) {
setErrors({password: response.data.password});
passwordRef.current.focus();
}
}
setLoading(false)
}
useEffect(() => {
console.log(errors);
});
return (
<>
<div className="content">
<Container className="pb-5">
<Row>
<Col lg="6" md="8" className="ml-auto mr-auto">
<Card className="bg-secondary border-0">
<CardHeader className="bg-transparent">
<div className="text-center">
<h2>Register</h2>
</div>
</CardHeader>
<CardBody className="px-lg-5 py-lg-5">
<Form role="form" onSubmit={handleSubmit}>
<FormGroup>
<label
className="form-control-label"
>
Email
</label>
<Input
name="email"
type="email"
innerRef={emailRef}
value={values.email || ""}
onChange={handleChange}
invalid={!!errors.email}
required
/>
<FormFeedback>{errors.email}</FormFeedback>
</FormGroup>
<FormGroup>
<label
className="form-control-label"
>
Password
</label>
<Input
name="password"
type="password"
innerRef={passwordRef}
value={values.password || ""}
onChange={handleChange}
invalid={!!errors.password}
required
/>
<FormFeedback>{errors.password}</FormFeedback>
</FormGroup>
<FormGroup>
<label
className="form-control-label"
>
Access Code
</label>
<Input
name="accessCode"
type="text"
innerRef={accessCodeRef}
value={values.accessCode || ''}
onChange={handleChange}
invalid={!!errors.accessCode}
required
/>
<FormFeedback>{errors.accessCode}</FormFeedback>
</FormGroup>
<Row className="my-4">
<Col xs="12">
<div
className="custom-control custom-control-alternative custom-checkbox">
<input
className="custom-control-input"
id="customCheckRegister"
type="checkbox"
required
/>
<label
className="custom-control-label"
htmlFor="customCheckRegister"
>
<span className="text-muted">
I agree with the{" "}
<a
href=""
target="_blank"
rel="noopener noreferrer"
>
Privacy Policy
</a>
</span>
</label>
</div>
</Col>
</Row>
<div className="text-center">
<Button disabled={loading} className="mt-4" color="info" type="submit">
Create account
</Button>
</div>
</Form>
</CardBody>
</Card>
</Col>
<Col md="4" className="ml-auto mr-auto">
<h2>Being a photographer is easier with <b className="text-primary">FOCAL</b></h2>
<ul>
<li>
<h4>Focal is great</h4>
</li>
<li>
<h4>Save time</h4>
</li>
<li>
<h4>More customers</h4>
</li>
</ul>
</Col>
</Row>
</Container>
</div>
</>
);
}
export default RegisterForm;
const useForm = (callback, validate) => {
const [values, setValues] = useState({});
const [errors, setErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = (event) => {
if (event) event.preventDefault();
setIsSubmitting(true);
};
useEffect(() => {
if (Object.keys(errors).length === 0 && isSubmitting) {
callback();
setIsSubmitting(false);
}
}, [callback, errors, isSubmitting]);
useEffect(() => {
setErrors(validate(values, errors));
}, [validate, values, errors]);
const handleChange = (event) => {
event.persist();
setValues(values => ({...values, [event.target.name]: event.target.value}));
setErrors(validate(values, errors));
};
return {
handleChange,
handleSubmit,
setErrors,
values,
errors
}
};
export default useForm;
export function registerFormValidation(values, errors) {
if (values.email === ""){
delete errors.email;
}
if (values.password) {
if (!verifyLength(values.password, PASSWORD_LENGTH)){
errors.password = "Password must be greater than 8 Characters";
} else {
delete errors.password;
}
}
if (values.accessCode === "") {
delete values.accessCode;
}
return errors
}```
I can appreciate that it's of interest to work on a custom hook but forms are ubiquitous and there are solid, proven means to work with them. IMHO Formik is probably the best.
With the three fields that you have there, you could implement something like the following:
import React from 'react';
import { Formik } from 'formik';
const BasicExample = () => (
<div>
<Formik
initialValues={{ email: '', password: '', accessCode: '' }}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
render={props => (
<form onSubmit={props.handleSubmit}>
<input
type="email"
onChange={props.handleChange}
onBlur={props.handleBlur}
value={props.values.email}
name="email"
/>
{props.errors.email && <div id="feedback">{props.errors.email}</div>}
<input
type="password"
onChange={props.handleChange}
onBlur={props.handleBlur}
value={props.values.password}
name="password"
/>
{props.errors.password && <div id="feedback">{props.errors.password}</div>}
<input
type="text"
onChange={props.handleChange}
onBlur={props.handleBlur}
value={props.values.accessCode}
name="accessCode"
/>
{props.errors.accessCode && <div id="feedback">{props.errors.acessCode}</div>}
<button type="submit">Submit</button>
</form>
)}
/>
</div>
);
Note that the above is just from memory - which to some extent speaks to it's simplicity. As initialValues are supplied to Formik, you can build complex component hierarchies without having to pass down form state but that's just one of the various benefits.
I have an assumption.
In registerFormValidation doesn't modify errors object. Create a new each time.
FIXED:
const useForm = (callback, validate) => {
const [values, setValues] = useState({});
const [errors, setErrors] = useState({});
const handleSubmit = (event) => {
if (event) event.preventDefault();
if (Object.keys(errors).length === 0){
callback();
}
};
const handleChange = (event) => {
event.persist();
setValues(values => ({...values, [event.target.name]: event.target.value}));
setErrors(validate({[event.target.name]: event.target.value}, errors));
};
return {
handleChange,
handleSubmit,
setErrors,
values,
errors
}
};
export default useForm;
got rid of useEffect!

How to maintain controlled input which are added dynamically on user click with React Hooks

I've got a form component, where you can add multiple inputs on click. I am using useState to store data from all of the inputs, but the problem is I am receiving a message that my inputs are uncontrolled
State data structure
const [formData, setFormData] = useState({
title: '',
titleNum: '',
meta: [
{
content: '',
contentNum: '',
details: '',
tags: ''
}
]
});
The idea is to dynamically add multiple objects via form to meta array
onChange events added to inputs
const { title, titleNum, meta } = formData;
const handleMainChange = e => {
const { name, value } = e.target;
setFormData({ ...formData, [name]: value });
};
const handleSubChange = (e, index) => {
const { name, value } = e.target;
let metaContent = [...meta];
metaContent[index] = { ...metaContent[index], [name]: value };
setFormData({ ...formData, meta: metaContent });
};
Adding and removing inputs
const handleAddInput = () => {
setFormData(prevState => ({
meta: [
...prevState.meta,
{ content: '', contentNum: '', details: '', tags: '' }
]
}));
};
const handleRemove = index => {
let metaContent = [...meta];
metaContent.splice(index, 1);
setFormData({ meta: metaContent });
};
Submit and looping through all META
const onFormSubmit = e => {
e.preventDefault();
createAccount(formData, history);
};
const renderList = meta.map((item, index) => {
console.log(item);
return (
<AddMeta
key={index}
index={index}
meta={item}
handleChange={e => handleSubChange(e, index)}
handleRemove={() => handleRemove(index)}
/>
);
});
AddMeta Component
const AddMeta = ({ index, meta, handleChange, handleRemove }) => {
return (
<Fragment>
<div className='row valign-wrapper'>
<div className='col s3'>
<h5 className='indigo-text text-lighten-1'>Add Meta - {index + 1}</h5>
</div>
<div className='col s9'>
<button onClick={() => handleRemove(index)} className='btn red'>
Remove Meta Content
</button>
</div>
</div>
<div className='form-group'>
<input
type='text'
placeholder='Content Text'
name='content'
value={meta.content || ''}
onChange={e => handleChange(e, index)}
autoComplete='off'
/>
</div>
<div className='form-group'>
<input
type='text'
placeholder='Content Number'
name='contentNum'
value={meta.contentNum || ''}
onChange={e => handleChange(e, index)}
autoComplete='off'
/>
</div>
<div className='form-group'>
<textarea
className='materialize-textarea'
type='text'
placeholder='Details'
name='details'
value={meta.details || ''}
onChange={e => handleChange(e, index)}
autoComplete='off'
/>
</div>
<div className='form-group'>
<input
type='text'
placeholder='Tags'
name='tags'
value={meta.tags || ''}
onChange={e => handleChange(e, index)}
autoComplete='off'
/>
</div>
</Fragment>
);
};
I appreciate any attempt to solve this problem.
Thanks!
Try removing the || '' on your inputs value. Their value should always be tied to your state (which should be '' when you add a new meta).

Resources