useState not working with render in React app - javascript

I am a beginner in React and trying to make a CRUD app. I have this code snipped where useState is being used but when I use the same in a class with render function it gives an error. Can someone explain me why and can convert this code to suit a class with render
export default function App(){
const[userName,setUserName]=useState('');
const[password,setPassword]=useState('');
return(
<div className="CreatePost">
<label>UserName</label>
<input type="text"
onChange={(e)=>{
setUserName(e.target.value);
}}
/>
<label>Password</label>
<input type="text"
onChange={(e)=>{
setPassword(e.target.value);
}}
/>
</div>
);
}

useState() only works in functional component. if you want to modify state in a class based component you have to do it with setState method. Something like this should work
export default class App extends React.Component{
constructor() {
this.state ={ userName : "" , password: "" }
}
render() {
return(
<div className="CreatePost">
<label>UserName</label>
<input type="text"
onChange={(e)=>{
this.setState( {userName : e.target.value} );
}}
/>
<label>Password</label>
<input type="text"
onChange={(e)=>{
this.setState( {password : e.target.value} );
}}
/>
</div>
);
}
}

You cannot use hook inside class component. Convert your existing component into the class based as following:
class App extends React.PureComponent {
state = {
userName: '',
password: '',
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
}
render () {
const { userName, password } = this.state;
return (
<div className="CreatePost">
<label>UserName</label>
<input type="text" value={userName} onChange={this.handleChange}/>
<label>Password</label>
<input type="text" value={password} onChange={this.handleChange}/>
</div>
)
}
}

Related

I want to redirect to a new page on react on a conditon

Error:Line 33:13: Expected an assignment or function call and instead saw an expression no-unused-expressions
I used the Route and Browser Router to create the link to the page.
I need to redirect to the home page on signing in.
import axios from 'axios'
import {Redirect} from 'react-router-dom'
import React,{Component} from 'react'
const url ="http://localhost:80/phpfile"
class Signup extends Component{
constructor(){
super();
this.state={
username:"",
password:"",
value:false
}
}
sign=e=>{
e.preventDefault();
const user={
"username":this.state.username,
"password":this.state.password
}
axios.post(url,user,{"header":{ "content-type": "application/json",}}
)
.then(result=>{if (result.data===true)
{
this.setState({value:true});
}
})
if(this.state.value){
<Redirect to='/'/>
}
}
render(){
const value= this.state.value;
return(
<div>
<form action="#">
<label> Username</label>
<input name="name" value="Enter the usrname" id ="name"
onChange={e => this.setState({ username: e.target.value })}/>
<label>Password</label>
<input type="password" placeholder="Enter Password" id="pass"
name="pass" onChange={e => this.setState({password: e.target.value })}/>
<botton onClick={e=>this.sign(e)}>Signin</botton>
</form>
</div>
)
}
}
export default Signup;
As you are not using state anywhere, you can add redirect instead of setting state:
...
.then(result=>{if (result.data===true)
{
return <Redirect to='/'/>
}
})
or if state requirement is there, then based on state you can add the Redirect in return statement of component
render(){
const value= this.state.value;
return(
<div>
{!value ?
(<form action="#">
<label> Username</label>
<input name="name" value="Enter the usrname" id ="name"
onChange={e => this.setState({ username: e.target.value })}/>
<label>Password</label>
<input type="password" placeholder="Enter Password" id="pass"
name="pass" onChange={e => this.setState({password: e.target.value })}/>
<botton onClick={e=>this.sign(e)}>Signin</botton>
</form>)
: (<Redirect to='/'/>)
}
</div>
)
}

How to pass the default value back as input value if you don't want the value to be changed?

I have assigned default values to the input tag. When I try to submit without changing the values of the input tag, the value passed is undefined.
What I want is that if the input value is changed, to update the state value with the new value and if the input tag value is not changed, then to pass the default value to the state.
I am new to React.
import React, { Component } from 'react';
import Firebase from '../Firebase';
import _ from 'lodash';
import '../App.css';
class Modify extends Component {
constructor(props) {
super(props);
//state
this.state = {
personDetails: {},
detail: ''
};
//bind
this.renderData = this.renderData.bind(this);
this.handleChange = this.handleChange.bind(this);
this.saveEdit = this.saveEdit.bind(this);
}
//lifecycle
componentDidMount() {
Firebase.database().ref('/nannydetails').on('value', (snapshot) => {
this.setState({
personDetails: snapshot.val()
})
})
}
//handle change
handleChange(event) {
this.setState({
[event.target.name]: event.target.value.toLowerCase()
});
}
//render data
renderData() {
return _.map(this.state.personDetails, (personDetail, key) => {
return(
<div className="pt-2 pb-1 m-2 border border-dark bg-warning row" key={key}>
<div className="col-md-3 col-xs-3 text-right">
<img src={require('./profile.png')} alt="cam"/>
</div>
<div className="col-md-9 col-xs-9 p-2">
<div className="headline">
<h1>Full Name: </h1>
<input className="form-control" type="text" name="fullName" defaultValue={personDetail.fullname} onChange={this.handleChange}/>
</div>
<div className="headline">
<h1>Contact Number: </h1>
<input className="form-control" type="text" name="phone" defaultValue={personDetail.phone} onChange={this.handleChange}/>
</div>
<div className="headline">
<h1>Experience: </h1>
<input className="form-control" type="text" name="experience" defaultValue={personDetail.experience} onChange={this.handleChange}/>
</div>
<div className="headline">
<h1>City: </h1>
<input className="form-control" type="text" name="city" defaultValue={personDetail.city} onChange={this.handleChange}/>
</div>
<div className="headline">
<h1>State: </h1>
<input className="form-control" type="text" name="state" defaultValue={personDetail.state} onChange={this.handleChange}/>
</div>
<button className="btn btn-success" type="button" onClick={() => this.saveEdit(key)}><i className="fa fa-pencil-square-o"></i> Save Edit</button>
<button className="btn btn-danger" type="button" onClick={() => this.handleDelete(key)}><i className="fa fa-trash"></i> Delete</button>
</div>
</div>
)
});
}
//handle save edit
saveEdit(key) {
// Firebase.database().ref(`/nannydetails/${key}`).push({
// fullname: this.state.fullname,
// phone: this.state.phone,
// experience: this.state.experience,
// city: this.state.city,
// state: this.state.state
// });
console.log(this.state.fullname);
console.log(this.state.phone);
console.log(this.state.experience);
console.log(this.state.city);
console.log(this.state.state);
}
//handle delete
handleDelete(key) {
const user= Firebase.database().ref(`/nannydetails/${key}`);
user.remove();
}
render() {
return (
<div className="container mt-4">
{this.renderData()}
</div>
);
}
}
export default Modify;
Update the change handler to update/mutate the existing state instead of adding a new property(key), i.e. on this.state.personDetails.X vs. this.state.X
//handle change
handleChange(event) {
// update the personDetails object you set in state on mount
const newPersonDetails = { ...this.state.personDetails };
newPersonDetails[event.target.name] = event.target.value.toLowerCase();
this.setState({
personDetails: newPersonDetails,
});
}
Make this as a controlled component. Provide a initial state in you component and all the updated will done into the state & that will directly reflect into your component.
Initial State:
this.state = {
personDetails: {
fullname :'test'
},
detail: ''
};
Input Field
input className="form-control" type="text" name="fullName" value={this.state.personDetail.fullname} onChange={this.handleChange}
onChange is only triggered when the value of input changes. The defaultValue can be defined in the initial state, and the defaultValue is overwritten when the value of input changes.
The best way to approach is to have a main component take data from any api (firebase in your case) and second child component which will be responsible to take input as props and return input(default/modified) on form action(submit). That way if data changes you get modified data else the default one.
class FormComp extends React.Component {
constructor(props) {
super(props);
this.state = {
name: this.props.form.name,
};
this.submit = this.submit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
submit(e) {
e.preventDefault();
console.log(this.state);
}
handleChange(e) {
this.setState({name: e.target.value});
}
handleChan
render() {
return (
<div>
<form onSubmit={this.submit}>
<input
type="text"
value={this.state.name}
onChange={this.handleChange}
/>
<button type="submit">Submit</button>
</form>
</div>
);
}
}
Refer to that fiddle for example. https://jsfiddle.net/papish19/ys6utv3k/7/

Where does redux-form's `meta : { touched, error }` live? Could I access it when not contained by renderField scope?

The redux-form documentation advises me to render my input and submit-validation errors like this.
const renderField = ({ input, placeholder, className, type, meta: { touched, error } }) => (
<div>
<input {...input} className={className} placeholder={placeholder} type={type}/>
{touched && error && <span><font color="red">{error}</font></span>}
</div>
)
Inside render(){return(<form> </form>)} you are then supposed to create your inputs like this (note component={renderField} in the next code line):
<Field type="password" placeholder="password" className="form-control" component={renderField} name="password"/>
I wanted to customize this in order to fit it better into my own work. But I cannot seem to find a way to target touched and error unless I place the component in renderField, I guess I am still missing some vital knowledge. Where are these meta: {touched, error} properties going exactly and if I can access them somewhere?
Below is my entire container file for your reference.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm } from "redux-form"
import Title from "../components/Title.js"
const renderField = ({ input, placeholder, className, type, meta: { touched, error } }) => (
<div className={"" + touched && error && "input_error_border"}>
<input {...input} className={className} placeholder={placeholder} type={type}/>
{touched && error && <span><font color="red">{error}</font></span>}
</div>
)
class RegisterForm extends React.Component {
constructor(props) {
super(props);
this.props = props;
}
is_registered(){
if(this.props.user.server && this.props.user.insert){
return (<div>
<p>Thank you for registering {this.props.user.first_name}</p>
<p>You will recieve an email with further instructions shortly.</p>
</div>)
}else{
return <div></div>
}
}
render() {
const { handleSubmit } = this.props
console.log(this.props)
return (
<form onSubmit={ handleSubmit } className="box-sizing mx-auto max_vertical_form_400">
<Title innerH="Register New User"/>
<div className="input-group-btn">
{this.is_registered()}
</div>
<div className="form-group">
<Field type="text" placeholder="first name" className="form-control" component={renderField} name="first_name" />
<Field type="text" placeholder="last name" className="form-control" component={renderField} name="last_name" />
</div>
<div className="form-group">
<Field type="text" placeholder="email" className="form-control" component={renderField} name="email"/>
</div>
<div className="form-group">
<Field type="text" placeholder="company" className="form-control" component={renderField} name="company"/>
<Field type="text" placeholder="department" className="form-control" component={renderField} name="department"/>
</div>
<div className="form-group">
<Field type="password" placeholder="password" className="form-control" component={renderField} name="password"/>
<Field type="password" placeholder="repeat password" className="form-control" component={renderField} name="password_repeated"/>
</div>
<div className="input-group-btn">
<button type="submit" className="btn btn-primary">Submit</button>
</div>
{/* <RegisterFormContainer />
<ThemeContainer /> */}
</form>
);
}
}
function validate(values){
const errors= {};
if(!values.password) errors.password = "missing password";
if (!values.email) {
errors.email = 'Required'
} else if (!/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = 'Invalid email address'
}
return errors;
}
RegisterForm = reduxForm({
form: "register_user_form",
validate
})(RegisterForm)
function mapStateToProps({ user }) {
return { user };
}
export default RegisterForm = connect(mapStateToProps, null)(RegisterForm)
You can use redux-form selectors, specifically getFormMeta to know which fields are dirty or touched and getFormSyncErrors to know the fields having errors.
In your code, you need to change to import the selectors
import { getFormMeta, getFormSyncErrors } from 'redux-form';
add it to your mapStateToProps which might look like this:
function mapStateToProps(state) {
return {
user: state.user,
metaForm: getFormMeta('register_user_form')(state),
formSyncErrors: getFormSyncErrors('register_user_form')(state),
};
}
and then you can reference in your component with this.props.metaForm and this.props.formSyncErrors

MDC-web not working as expected

import React, { Component } from "react";
import { MDCTextfield, MDCTextfieldFoundation } from "#material/textfield";
import { MDCFormField, MDCFormFieldFoundation } from "#material/form-field";
class Material extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.textfield_ = new MDCTextfieldFoundation(
document.querySelector(".mdc-textfield")
);
}
componentDidMount() {
const textfield = new MDCTextfield(
document.querySelector(".mdc-textfield")
);
}
render() {
return (
<div>
<form>
<div className="mdc-textfield">
<input type="email" id="" className="mdc-textfield__input" />
<label htmlFor="email" className="mdc-textfield__label">
Email address1
</label>
</div>
<div className="mdc-textfield">
<input type="email" id="email" className="mdc-textfield__input" />
<label htmlFor="email" className="mdc-textfield__label">
Email address3
</label>
</div>
</form>
</div>
);
}
}
export default Material;
this is my page Material.js in my project and here i'm using material-components-web library.I want input to animate which was working fine.
but i wanted to use two inputs with same animation.i used two identical div of class mdc-textfield.But now only 1st div with class mdc-textfield is working fine but 2nd shows no animation.please help
This is because document.querySelector(".my_class") returns the first elements that it finds with "my_class". You can uses different ref names for the textfiels like this:
componentDidMount() {
const textfield_email = new MDCTextfield(this.refs.textfield_email);
const textfield_name = new MDCTextfield(this.refs.textfield_name);
}
...
<label ref="textfield_email" className="mdc-textfield ">
<input name="email" className="mdc-textfield__input" onChange={this.handleChange} value={this.state.email} />
<span className="mdc-textfield__label">Email</span>
</label>
<label ref="textfield_name" className="mdc-textfield ">
<input name="name" className="mdc-textfield__input" onChange={this.handleChange} value={this.state.name} />
<span className="mdc-textfield__label">Name</span>
</label>
I usually wrap the MDC Components in React JS Components. Here would be a very stripped down example for a textfield:
import React from 'react';
import { MDCTextfield } from '#material/textfield/dist/mdc.textfield';
class Textfield extends React.Component {
componentDidMount() {
const textfield = new MDCTextfield(this.refs.textfield);
}
static defaultProps = {
label: "",
className: "",
name: "",
onChange: function() {}
}
render() {
return (
<div className={this.props.className}>
{/* Text field component */}
<label ref="textfield" className="mdc-textfield " id={this.props.id} >
<input name={this.props.name} className="mdc-textfield__input" onChange={this.props.onChange} value={this.props.value} />
<span className="mdc-textfield__label">{this.props.label}</span>
</label>
</div>
);
}
}
export default Textfield
Then use like this:
<Textfield onChange={this.handleChange} value={this.state.value} label="email" name="email"></Textfield>
EDIT
If you want to use MDC with ReactJS and want an easy life, I would suggest using: RMWC (https://github.com/jamesmfriedman/rmwc) and hopefully soon the official React Wrapper from Google (https://github.com/material-components/material-components-web-react)

Handle change event not working for input types?

I am new to react… my handle change event is not working while typing text into an input. How do I go about fixing that? I want to handle both inputs with the same handle change.
import React from 'react'
import TextField from 'material-ui/TextField'
class Settings extends React.Component {
constructor(props) {
super(props)
this.state = {
first_name:'',
last_name:''
}
}
handleChange(e){
var first_name = e.target.first_name
var last_name = e.target.last_name
var state = this.state
state[first_name] = e.target.value
state[last_name] = e.target.value
this.setState(state)
}
render() {
return (
<div>
<TextField hint text="First Name" id="user_first_name" floatingLabelFixed="editprofile" onChange={this.handleChange.bind(this)} name="user[first_name]" size="30" type="text" value={this.state.first_name} />
<TextField hint text="Last Name" id="user_last_name" floatingLabelFixed="editprofile" name="user[last_name]" onChange={this.handleChange.bind(this)} size="30" type="text" value={this.state.last_name} />
</div>
)
}
}
Based on id you should update the state and not both on them together. Try the below method. Also change the ids
import React from 'react'
import TextField from 'material-ui/TextField'
class Settings extends React.Component {
constructor(props) {
super(props)
this.state = {
first_name:'',
last_name:''
}
}
handleChange(e){
this.setState({[e.target.id]: e.target.value});
}
render() {
return (
<div>
<TextField hint text="First Name" id="first_name" floatingLabelFixed="editprofile" onChange={this.handleChange.bind(this)} name="user[first_name]" size="30" type="text" value={this.state.first_name} />
<TextField hint text="Last Name" id="last_name" floatingLabelFixed="editprofile" name="user[last_name]" onChange={this.handleChange.bind(this)} size="30" type="text" value={this.state.last_name} />
</div>
)}
}
as you're using material-ui/TextField component updating state by target.id can't work, because TextField component doesn't pass your id to its input, so you can do it by adding second parameter to your handleChange function, like this:
import React from 'react'
import TextField from 'material-ui/TextField'
class Settings extends React.Component {
constructor(props) {
super(props)
this.state = {
first_name:'',
last_name:''
}
}
handleChange(value, param){
this.setState({[param]: value});
}
render() {
return (
<div>
<TextField hint text="First Name" id="first_name" floatingLabelFixed="editprofile" onChange={(e) => this.handleChange(e.target.value, 'first_name')} name="user[first_name]" size="30" type="text" value={this.state.first_name} />
<TextField hint text="Last Name" id="last_name" floatingLabelFixed="editprofile" name="user[last_name]" onChange={(e) => this.handleChange(e.target.value, 'last_name')} size="30" type="text" value={this.state.last_name} />
</div>
)}
}
I think, issue is you are updating both the fields by the same value, write it like this:
handleChange(e){
var obj = {}
obj[e.target.name] = e.target.value
this.setState(obj);
}
And assign the same name as the state variable names, like this:
<TextField ... name='first_name' value={this.state.first_name} onChange={this.handleChange.bind(this)}/>
<TextField ... name='last_name' value={this.state.last_name} onChange={this.handleChange.bind(this)} />
Use this:
class Settings extends React.Component {
constructor(props) {
super(props)
this.state = {
first_name:'',
last_name:''
}
}
handleChange(e){
let obj = {};
obj[e.target.name] = e.target.value;
this.setState(obj);
}
render() {
return (
<div>
<TextField hintText="First Name" id="first_name" floatingLabelFixed="editprofile" onChange={this.handleChange.bind(this)} name="first_name" size="30" type="text" value={this.state.first_name} />
<TextField hinText="Last Name" id="last_name" floatingLabelFixed="editprofile" name="last_name" onChange={this.handleChange.bind(this)} size="30" type="text" value={this.state.last_name} />
</div>
)}
}
class Settings extends React.Component {
constructor(props) {
super(props)
}
handleChange=(e)=>{
const {name,value}=e.target;
this.setState({[name]=value});
}
render() {
return (
<div>
<TextField hintText="First Name" floatingLabelFixed="editprofile" onChange={this.handleChange} name="first_name" size="30" type="text" />
<TextField hinText="Last Name"floatingLabelFixed="editprofile" name="last_name" onChange={this.handleChange} size="30" type="text"/>
</div>
)}
}

Categories

Resources