Can't update state using useState - javascript

I'm trying to update the state of my component with useState in a register functional component。
when user input an invalid email address and click the submit button,
the following piece of code will return an error message
let response= await axios.post("/api/user/register",new_user,config);
I want to set error message into formData with this piece of code .
let response= await axios.post("/api/user/register",new_user,config);
if(response.data.errnum!==0){
setFormData({...formData,errors:response.data.message})
console.log(formData);
}
but the value of errors is empty,like this
What should I do to set error message into formData?
Here is my code:
import React ,{useState}from 'react'
import axios from "axios"
function Register() {
const [formData,setFormData]=useState({
name:"",
email:"",
password:"",
password2:"",
errors:{}
});
const {name,email,password,password2}=formData;
const setValue= e =>setFormData({...formData,[e.target.name]:e.target.value})
const submitData=async (e) =>{
e.preventDefault();
if(password!==password2){
console.log("passwords do not match ");
}else{
let new_user={name,email,password,}
try{
let config={
header:{
'Content-Type':'applicaiton/json'
}
}
let response= await axios.post("/api/user/register",new_user,config);
if(response.data.errnum!==0){
setFormData({...formData,errors:response.data.message})
console.log(formData);
}
}catch(error){
console.error(error);
}
}
}
return (
<div>
<section className="container">
<h1 className="large text-primary">Sign Up</h1>
<p className="lead"><i className="fas fa-user"></i> Create Your Account</p>
<form className="form" onSubmit={e=>submitData(e)}>
<div className="form-group">
<input
type="text"
placeholder="Name"
name="name"
value={name}
onChange={e=>setValue(e)}
required />
</div>
<div className="form-group">
<input
type="email"
placeholder="Email Address"
onChange={e=>setValue(e)}
value={email}
name="email" />
<small className="form-text">This site uses Gravatar so if you want a profile image, use aGravatar email</small>
</div>
<div className="form-group">
<input
type="password"
placeholder="Password"
onChange={e=>setValue(e)}
value={password}
name="password"
minLength="6"
/>
</div>
<div className="form-group">
<input
type="password"
placeholder="Confirm Password"
onChange={e=>setValue(e)}
value={password2}
name="password2"
minLength="6"
/>
</div>
<input type="submit" className="btn btn-primary" value="Register" />
</form>
<p className="my-1">
Already have an account? Sign In
</p>
</section>
</div>
)
}
export default Register

I think what you are doing wrong is that you are saving and object inside another object
const [formData,setFormData]=useState({
name:"",
email:"",
password:"",
password2:"",
errors:{}
});
formData is an object while errors is also an object.To go for a better approach make a seperate state for errors and append all the errors coming through those messages in an error object.
If you write a message in errors object where it is defined it will give you error
errors:{"hi","bye"}

There is no issue in your code. What you are trying to do is console the state as soon as you are setting it up.
setState is asynchronous which means you can’t call it on one line and assume the state has changed on the next.
If you check React docs
setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value. There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.
I'd suggest you use useEffect and then check for change in data of your state.
useEffect(() => {
console.log(formData)
}, [formData])

Related

Can't convert input element to re-usable component in react js

I created a login form and now I want to convert my input fields to re- usable component. I created separate common input.jsx file. This is input.jsx file's code.
import React from "react";
const Input = ({ name, label, value, onChange }) => {
return (
<div className="form-group">
<label htmlFor={name}>{label}</label>
<input
value={value}
onChange={onChange}
id={name}
name={name}
type="text"
className="form-control"
/>
</div>
);
};
export default Input;
and imported it to my loginForm.jsx. Here is my loginForm.jsx render method
handleChange = ({ currentTarget: input }) => {
const account = { ...this.state.account };
account[input.name] = input.value;
this.setState({ account });
};
render() {
const { account } = this.state;
return (
<div>
<h1>Login</h1>
<form onSubmit={this.handleSubmit}>
<Input
name="username"
value={account.username}
label="Username"
onChange={this.handleChange}
/>
<Input
name="password"
value={account.password}
label="Password"
onChange={this.handleChange}
/>
<button className="btn btn-primary">Login</button>
</form>
</div>
);
}
But after adding below code to my loginForm.jsx,
<Input
name="username"
value={account.username}
label="Username"
onChange={this.handleChange}
/>
code and deleted previous code ,
<div className="form-group">
<label htmlFor="username">Username</label>
<input
value={account.username}
name="username"
onChange={this.handleChange}
ref={this.username}
id="username"
type="text"
className="form-control"
/>
</div>
suddenly my login page not loading.(Empty page).
My login page's console showing below error.
The above error occurred in the <LoginForm> component:
at LoginForm (http://localhost:3000/main.5d4e82bfe117bc198b43.hot-update.js:27:5)
at Route (http://localhost:3000/static/js/bundle.js:54444:5)
at Switch (http://localhost:3000/static/js/bundle.js:54739:5)
at main
at App
at Router (http://localhost:3000/static/js/bundle.js:54612:5)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:53870:5)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.

Render components based on state

I am working on a user registration/ log in page. I have two forms, a signUp form and a logIn form, and some state called signInState that determines which user form to display. I have two buttons that toggle the signInState, and if the signInState is true, I want it to display the log in form, if its false, I want to display the sign up form. The state is changing, but for some reason the conditional rendering is not working. Can someone help me figure out why my toggleSignInState doesn't change what's being rendered on the page? Thanks
Here is my react code for the signInPage itself
import React from 'react'
import SignUp from './SignUp'
import LogIn from './LogIn'
export default function SignInPage() {
const [signInState, setSignInState] = React.useState(true);
function toggleSignIn(event) {
console.log(event.target.id)
setSignInState(event.target.id);
/*setSignInState(event.target.value);*/
}
return (
<div className="signInPage">
<div className="signInPageFormContainer">
<p>{signInState}</p>
{!signInState && <SignUp /> }
{signInState && <LogIn /> }
<div className="signUpPageToggleContainer">
<button onClick={toggleSignIn} id='true'>Log In</button>
<button onClick={toggleSignIn} id='false'>Sign Up</button>
</div>
</div>
</div>
)
}
here is the code for the signUp form
import React from 'react'
export default function SignUp() {
return(
<form className="signUpForm">
<input
name="username"
type="text"
placeholder="Username"
className="signUpInput"
/>
<input
name="email"
type="text"
placeholder="Email"
className="signUpInput"
/>
<input
name="password"
type="text"
placeholder="Password"
className="signUpInput"
/>
<input
name="confirmPassword"
type="text"
placeholder="Confirm password"
className="signUpInput"
/>
<div>
<button>Sign Up</button>
<button>Cancel</button>
</div>
</form>
)
}
and here is the code for the log in form
import React from "react";
export default function LogIn() {
/*functions for log in procedure*/
return (
<form className="logInForm">
<input
placeholder="Username"
name="username"
type="text"
id="username"
className="logInFormInput"
/>
<input
placeholder="Password"
name="password"
type="text"
id="password"
className="logInFormInput"
/>
<div className="logInFormButtonContainer">
<button className="logInFormButton">Log In</button>
<button className="logInFormButton">Cancel</button>
</div>
</form>
)
}
Element attributes are strings. The string 'true' is not the same as the boolean true, and the string 'false' is not the same as the boolean false. Both 'true' and 'false' are truthy, so signInState is always truthy.
While you could perform string comparisons inside toggleSignIn to determine what to pass to the state setter, calling the state setter inline in the buttons would be easier.
<button onClick={() => { setSignInState(true); }}>Log In</button>
<button onClick={() => { setSignInState(false); }}>Sign Up</button>
Here the id from event object will always be Boolean true as they are not booleans they are strings, i.e., whatever you keep as value in a DOM attribute it would be a string in most of the cases and any string except empty string "" is true ...
The answer from CertainPerformance is better and easy to understand
In case you want to keep your code same and changing a little as below should work
function toggleSignIn(event) {
setSignInState(event.target.id === "true" ? true : false);
}

Reactjs Usestate hook not sending data properlty to database

i know this is very easy question , but i am new with MERN technology. i am sending my data using React frontend to json-server npm module , all the codes works properly even though the data stored to backend smoothly . but the problem is that frontend data send extra fields to backend server which i don't want . you can see image there are 3 object 1st two object i have stored manually and third one i stored using React frontend application . the third one json-object stored extra fields are highlited here which i dont want . i am upload my working code please guide me .
//RegisterUser react Component :
import React from 'react'
import { useState } from 'react';
import loginImage from '../images/login2.jpeg';
import { NavLink } from 'react-router-dom';
import { addUser} from '../Service/api';
const initialValues = {
name:"",
username:"",
email:"",
phone:"",
}
const RegisterUser = () => {
const [user , setUser]= useState([initialValues]);
const { name,username, email, phone,} = user;
const style = {
color: 'black',
textAlign:'center'
};
const onValueChange= (e)=>{
console.log(e.target.Object);
setUser({...user, [e.target.name]:e.target.value})
console.log(user)
}
const addUserDetails= async()=>{
await addUser(user);
}
return (
<div>
<div>
<div className="container login-container">
<div className="row login-form-1">
<div className="col-md-6 ">
<h3 style={style}>Registration</h3>
<form>
<div className="form-group">
<input type="text" className="form-control" onChange={(e)=> onValueChange(e)} name="name" value={name} placeholder="Your Name *" />
</div>
<div className="form-group">
<input type="text" className="form-control" onChange={(e)=> onValueChange(e)} name="username" value={username} placeholder="username *" />
</div>
<div className="form-group">
<input type="text" className="form-control" onChange={(e)=> onValueChange(e)} name="email" value={email} placeholder="Your Email *" />
</div>
<div className="form-group">
<input type="text" className="form-control" onChange={(e)=> onValueChange(e)} name="phone" value={phone} placeholder="Mobile Number *" />
</div>
<div className="form-group">
<input type="submit" className="btnSubmit" onClick={()=> addUserDetails()} defaultValue="Login" />
</div>
</form>
</div>
<div className="col">
<img className="loginpic" src={loginImage} alt="login Image"/>
<div className="col">
<NavLink to="/login" className="signupIs" >I have already account</NavLink>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
export default RegisterUser
Api file
import axios from 'axios';
const url = 'http://127.0.0.1:3003/users';
export const getUsers = async ()=>{
return await axios.get(url);
}
export const addUser = async(user)=>{
return await axios.post(url,user);
}
again i am informing that the code is running no error while executing , but the issue is getting extra data field from React Frontend
When you first initialize your "user", you create it as an array:
const [user , setUser]= useState([initialValues]);
// ^---- here ---^
Then later you interpret the array as an object and add properties to it:
setUser({...user, [e.target.name]:e.target.value})
When doing so, that initial "user" would be a property called "0" since it's the first element of the array. So those "extra properties" are simply the initial state.
It sounds like what you intended was not to use an array at all:
const [user, setUser] = useState(initialValues);

Form Submit using reactjs

I am new in reactjs. I am creating a sample project using reactjs. First I am getting error like state is null. After setting intial state i am getting error
I got Warning: valueLink prop on input is deprecated; set value and onChange instead
I know there are many question related to this but my problem is not solved please help.
Here is code:
import React, {Component} from 'react';
import {Link} from 'react-router'
import validator from 'validator';
import LinkedStateMixin from 'react-addons-linked-state-mixin';
module.exports = React.createClass({
mixins: [LinkedStateMixin],
getInitialState() {
return {};
},
saveData: function(){
//console.log(this.state)
},
render () {
return (
<form>
<div className="page-content container">
<div className="row">
<div className="col-md-4 col-md-offset-4">
<div className="login-wrapper">
<div className="box">
<div className="content-wrap">
<h6>Sign Up</h6>
<input className="form-control" name ="email" placeholder="E-mail address" type="text" valueLink={this.linkState('email')}/>
<input className="form-control" name="password" placeholder="Password" type="password"/>
<input className="form-control" placeholder="Confirm Password" type="password" />
<div className="action">
<button type="button" className ="btn btn-primary signup" onClick={this.saveData}>Sign Up</button>
</div>
</div>
</div>
<div className="already">
<p>Have an account already?</p>
<Link to ="/reactApp/">Login</Link>
</div>
</div>
</div>
</div>
</div>
</form>
)
}
});
Please read more about the fundamentals of React and handling state in forms in the React documentation. No mixins or anything complicated required. Also as stated above "ReactLink is deprecated as of React v15. The recommendation is to explicitly set the value and change handler, instead of using ReactLink."
Each of your text inputs should have a change handler just like the error message says... There are many ways you could accomplish this but below is a basic example. Check out the snippet below in a fiddle here https://jsfiddle.net/09623oae/
React.createClass({
getInitialState: function() {
return({
email: "",
password: "",
passwordConfirmation: ""
})
},
submitForm: function(e) {
e.preventDefault()
console.log(this.state)
},
validateEmail: function(e) {
this.setState({email: e.target.value})
},
validatePassword: function(e) {
this.setState({password: e.target.value})
},
confirmPassword: function(e) {
this.setState({passwordConfirmation: e.target.value})
},
render: function() {
return (
<form onSubmit={this.submitForm}>
<input
type="text"
value={this.state.email}
onChange={this.validateEmail}
placeholder="email"
/>
<input
type="password"
value={this.state.password}
onChange={this.validatePassword}
placeholder="password"
/>
<input
type="password"
value={this.state.passwordConfirmation}
onChange={this.confirmPassword}
placeholder="confirm"
/>
</form>
)
}
});
Solution
You cannot use valueLink anymore, instead use onChange react event to listen for input change, and value to set the changed value.
class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: 'Hello!'};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
return (
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
);
}
Clarification
Notice that since the value is set from a state, it will only get updated from changing the attached state, writing in the input does nothing, unless you listen for the input changed (via onChange event) and update the state accordingly.
source: from React documentation
You should set your state to atleast empty initially, if you want to access it at a later point of time. Something similar to below will do
getInitialState() {
return {};
},
ReactLink Without valueLink
You can change with
<input type="text" value={valueLink.value} onChange={handleChange} />
Reference:
https://facebook.github.io/react/docs/two-way-binding-helpers.html
This warning happens because the React Link was deprecated in React 0.15:
ReactLink is deprecated as of React v15. The recommendation is to
explicitly set the value and change handler, instead of using
ReactLink.
So, instead of use this.linkState('email') and valueLink:
<input className="form-control"
name ="email"
placeholder="E-mail address"
type="text"
valueLink={this.linkState('email')}/>
Use this.state.email and an onChange function:
callThisWhenChangeEmail: function(emailFromInput) {
this.setState({
email: emailFromInput
});
},
render () {
/* the existent code above */
<input className="form-control"
name ="email"
placeholder="E-mail address"
type="text"
value={this.state.email}
onChange={this.callThisWhenChangeEmail}/>
/* the existent code below */
}
When the user type some e-mail in the input, the function callThisWhenChangeEmail is called, receiving the e-mail as parameter (emailFromInput). So, you only need to set this e-mail in the state.

When do I have access to props in the react class?

I am passing a meteor collection as a prop in one of my components and trying to figure it out when do I actually receive props?
I tried accessing (for e.g. this.props.userData) the props in getInitialState is says undefined, then I tried accessing it in componentDidMount it says undefined, but in render method it works fine.
Which method before or after render can tell me that I have access to props? I want to initialize the state with the values props will have.
for example in the code below I get an error saying that userData is undefined.
getInitialState(){
return{
firstName : this.props.userData.firstName
}
}
Edit
So I am doing something like this, I am using props just to initialize the state variable.
export default React.createClass({
getInitialState(){
return {
email : this.props.user.email
}
},
onFormSubmit(event){
event.preventDefault();
},
onTextFieldChange(event){
switch (event.target.name) {
case "email":
this.setState({
email:event.target.value
});
break;
}
},
render() {
console.log(this.props.user.email);
return (
<div className="panel panel-default">
<div className="panel-heading">
<h3 className="panel-title text-center"><strong>Sign in with Existing Account</strong></h3>
</div>
<form className="form-horizontal" id="frmSignIn" role="form" onSubmit={this.onFormSubmit}>
<div className="modal-body">
<div className="form-group">
<label className="col-xs-4 control-label">Email</label>
<div className="col-xs-8">
<input type="email" id="email" name="email" className="form-control"
value={this.state.email}
onChange={this.onTextFieldChange}
placeholder="example#domain.com"
required/>
</div>
</div>
<div className="form-group">
<label className="col-xs-4 control-label">Password</label>
<div className="col-xs-8">
<input type="password" id="password" name="password" className="form-control"
placeholder="Password"
required/>
<label id="signin-error" className="error"> </label>
</div>
</div>
</div>
<div className="panel-footer">
<label className="col-xs-4 control-label"></label>
<div className="col-xs-8">
<input type="submit" className="btn btn-primary pull-right" value="SignIn"/>
</div>
</div>
</form>
</div>
);
}
});
The component receives the initial properties immediately on instantiation. Actually it is the first argument of the constructor:
class MyComp extends React.Component {
constructor (props) {
super(props)
// do something with props
}
componentWillReceiveProps (nextProps) {
// properties changed
}
}
In your case my best guess is that the parent component does not yet have your property ready. You can track the passed property by observing them in the constructor and in a componentWillReceiveProps(nextProps) function.
Meteor synchronises user data just like any other collection with the server. It means that initially Meteor.user() will return undefined, and your component doesn't receive the prop. Later when the user document is updated, your component's props are updated, too. You can catch this event by implementing function componentWillReceiveProps(newProps) {...}.

Categories

Resources