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.
Related
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.
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])
New to react so I apologize if the solution obvious. Working on a registration form that should create a new account on submit using ajax. I know that I'm supposed to use onChange to gather the information is submitted. After seeing a number of examples I am still unable to get my code to work.
I know that the ajax call for POST works because I put in information myself on vscode to test if on submit it will create which it did. I am having issues with the transition from onChange to my submit form. Hope that was clear. Thank you
I've tried creating a onChange function for my registration template. I am unable to get the results that I've been hoping for
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
payload: {
firstName: "",
lastName: "",
email: "",
password: "",
passwordConfirm: ""
}
};
}
handleChange = event => {
let name = event.target.name;
let value = event.target.value;
this.setState({
[name]: value,
[name]: value,
[name]: value,
[name]: value,
[name]: value
});
};
onClickHandler = evt => {
evt.preventDefault();
let payload = this.state;
console.log(payload);
debugger;
registerService
.register(payload)
.then(this.onActionSuccess)
.catch(this.onActionError);
};
onActionSuccess = response => {
console.log(response);
};
onActionError = errResponse => {
console.log(errResponse);
};
<!-- -->
render() {
return (
<main role="main">
<div className="container">
<h1 id="title" align="center">
Register User
</h1>
</div>
<div className="container">
<div className="col-sm-4 col-sm offset-4">
<form className="form">
<div className="form-group">
<label htmlFor="this.state.firstName">First Name</label>
<input
placeholder="First Name"
type="text"
id="this.state.firstName"
className="form-control"
name="firstName"
value={this.state.firstName}
onChange={this.handleChange}
/>
</div>
<div className="form-group">
<label htmlFor="this.state.lastName">Last Name</label>
<input
placeholder="last Name"
type="text"
id="this.state. lastName"
className="form-control"
value={this.state.lastName}
onChange={this.handleChange}
/>
<div className="form-group">
<label htmlFor="register-email">Email</label>
<input
placeholder="Enter Email"
type="text"
className="form-control"
id="register-email"
value={this.state.email}
onChange={this.handleChange}
/>
</div>
</div>
<div className="form-group">
<label htmlFor="register-password">Password</label>
<input
placeholder="Password"
type="password"
id="register-password"
`enter code here`className="form-control"
value={this.state.password}
onChange={this.handleChange}
/>
</div>
<div className="form-group">
<label htmlFor="register-passwordConfirm">
Confirm Password
</label>
<input
placeholder="Confirm Password"
type="password"
id="register-passwordConfirm"
className="form-control"
value={this.state.passwordConfirm}
onChange={this.handleChange}
/>
</div>
<button onClick={this.onClickHandler} className="btn btn-
primary">
Submit Form
</button>
I am expecting to create a new profile when clicking submit via POST ajax call
Your handleChange function should be
handleChange = event => {
let { name, value } = event.target;
this.setState({
[name]: value,
});
};
You always call your handleChange once at a time. Every time you change something on the input, the function gets different name and different value, which is suffice to add/update the your state.
And I noticed that you also have payload object in state. Modify the state like
this.state = {
firstname: '',
....
}
If you really want to use like
this.state = {
payload: {
firstName: '',
....
}
};
Your onChange function should look like,
handleChange = event => {
let { name, value } = event.target;
this.setState({
payload: {
...this.state.payload, // don't forget to copy all the other values
[name]: value,
}
});
};
The constructor and function:
constructor(props) {
super(props);
this.state = {
tagline: 'We rank what people are talking about.',
year: new Date().getFullYear()
};
this.onFormSubmit = this.onFormSubmit.bind(this);
}
onFormSubmit(e) {
console.log('onFormSubmit', e)
console.log('this.state', this.state);
};
The form (classNames removed for clarity):
<form onSubmit={ this.onFormSubmit }>
<div className="fl w100">
<div>
<input type="text" id="email" value={ this.state.email }/>
<label htmlFor="email">Email</label>
</div>
</div>
<div className="fl w100">
<div>
<input type="password" id="password" value={ this.state.password }/>
<label htmlFor="password">Password</label>
</div>
</div>
<button type="submit">
Login
</button>
</form>
This is what logs out, note no email or password information:
Full Login component code
import React from 'react';
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
tagline: 'We rank what people are talking about.',
year: new Date().getFullYear()
};
this.onFormSubmit = this.onFormSubmit.bind(this);
}
onFormSubmit(e) {
console.log('onFormSubmit', e)
console.log('this.state', this.state);
};
render() {
return (<div className="app">
<div className="welcome">
<header>
<div className="wikitags-logo">
<img src="imgs/wikitags-logo.png"/>
</div>
<h2>Admin Portal</h2>
<p>{ this.state.tagline }</p>
</header>
<section className="login-form">
<form onSubmit={ this.onFormSubmit }>
<div className="fl w100">
<div className="mdl-textfield mdl-js-textfield">
<input className="mdl-textfield__input" type="text" id="email" value={ this.state.email }/>
<label className="mdl-textfield__label" htmlFor="email">Email</label>
</div>
</div>
<div className="fl w100">
<div className="mdl-textfield mdl-js-textfield">
<input className="mdl-textfield__input" type="password" id="password" value={ this.state.password }/>
<label className="mdl-textfield__label" htmlFor="password">Password</label>
</div>
</div>
<button type="submit" className="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent">
Login
</button>
</form>
</section>
<footer>
© { this.state.year } WikiTags
</footer>
</div>
</div>);
}
}
export default Login;
Suggestions:
1. You are using value property with input fields but you didn't defined the onChange method so your input fields will be read-only because state value will not get updated.
2. You need to define a onChange event will all the input fields or make them uncontrolled element by removing the value property.
3. In case of uncontrolled element define the ref to each field and to access the value use this.ref_name.value.
By Defining the onChange event:
Define the name property to each input element (name should be same as state variable name it will help to update the state and we can handle all the change in single onChange function) like this:
<input type="text" name='value' value={this.state.value} onChange={(e) => this.handleChange(e)} />
handleChange(e){
this.setState({[e.target.name]: e.target.value})
}
By Uncotrolled element:
<input type="text" ref={el => this.el = el} />
Now inside onSubmit function use this.el.value to access he values of this input field.
Check this answer for reference: https://stackoverflow.com/a/43695213/5185595
You are not getting email or password information because you're passing in the state console.log('this.state', this.state); and you haven't set a state for the email and password.
Now, you got two options:
Set the state and get the form info from there
Pass the input value to a function that handles the info
For option 1, you'll need to set a state for your email and password (although setting a state for a password is not recommended) and an onChange event handler on the input(s).
Set up your onChange event handlers.
<form onSubmit={ this.onFormSubmit }>
<input type="text" id="email" onChange={this.handleEmailChange} value={ this.state.email } />
<input type="password" id="password" onChange={this.handlePasswordChange} value={ this.state.password } />
<button type="submit">
Login
</button>
</form>
And the functions to set the email and password states.
handleEmailChange(event) {
this.setState({ email: event.target.value });
}
handlePasswordChange(event) {
this.setState({ password: event.target.value });
}
And don't forget to initialize the state for your email and password in the constructor and bind the functions.
constructor(props) {
super(props);
this.state = {
email: '',
password: ''
};
this.handleEmailChange = this.handleEmailChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
}
And you're done! Then on the onFormSubmit function just access the email and password values from the state this.state.email and this.state.password and do whatever you like.
Now for option 2, you can just pass in the event.target.value of the inputs, those are the values for the email and the password, and pass those values to a form event handler onSubmit function, from there you can do whatever you want (set the state or update the email and password, change them, whatever).
<form onSubmit={ this.onFormSubmit }>
<input type="text" id="email" name="theEmail" />
<input type="password" id="password" name="thePassword" />
<button type="submit">
Login
</button>
</form>
And the onFormSubmit function.
onFormSubmit(event) {
const email = event.target.theEmail.value;
const password = event.target.thePassword.value;
// do stuff
console.log('Email:', email);
console.log('Password:', password);
};
The easier and recommended way to accomplish what you're trying to do is the option 2.
Remember, the less state your app handles the better.
So how I would approach this is to store the values in your state using what is called a controlled component. Making a controlled component is very simple, this is a basic implementation:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
The key here is the handleChange function, and the onChange attribute. Every time the input field changes, the handleChange function is going to be called and the state will be updated.
You can find more info form the documentation here: https://facebook.github.io/react/docs/forms.html
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) {...}.