React Js : How to use UseState In CallBack? - javascript

I have below code :
import React,{useState} from 'react'
function ReactForm() {
const iState =[{
Name : '',
Email :'',
Salary :0
}]
const [state, setstate] = useState(iState);
function validationHandler()
{
console.log(state);
}
return (
<div>
Name : <input type="text" onChange={(e)=>{setstate(...state, state.Name=e.target.value)}}></input>
<br></br>
Email : <input type="text" onChange={(e)=>{setstate(...state, state.Email=e.target.value)}}></input>
<br></br>
Salary : <input type="text" onChange={(e)=>{setstate(...state, state.Salary=e.target.value)}}></input>
<br></br>
<button onClick={validationHandler}>Validate Us</button>
</div>
)
}
export default ReactForm
I am performing basic validations here. I am receiving error : TypeError: state is not iterable
After going through few links on stackoverflow , I added - [ ] over state , but it did not helped.
EDIT 1 :
After Adding :- setstate({...state, state.Name: e.target.value}) : Unexpected token, expected "," (18:79)

Instead of having the setState called for each of the inputs you can make use of the name attribute and can refactor the code as below
import React, {useState} from 'react';
function ReactForm() {
const [state, setstate] = useState({
Name: '',
Email: '',
Salary: 0,
});
const handleChange = (e) => {
const {name, value} = e.target;
setstate((prevState) => ({...prevState, [name]: value}));
};
function validationHandler() {
console.log(state);
}
return (
<div>
Name :{' '}
<input
type="text"
value={state.Name}
name="Name"
onChange={handleChange}
/>
<br></br>
Email :{' '}
<input
type="text"
value={state.Email}
name="Email"
onChange={handleChange}
/>
<br></br>
Salary :{' '}
<input
type="text"
value={state.Salary}
name="Salary"
onChange={handleChange}
/>
<br></br>
<button onClick={validationHandler}>Validate Us</button>
</div>
);
}
export default ReactForm;
Refer:
Controlled Component

Your initial state is an array of objects. I'm not sure whether this is what you are looking for.
Assume your iState is (Just an object)
const iState = {
Name: '',
Email: '',
Salary: 0
}
Then you should do something like this in your onChange listener
// setState should use camel case for best pratice BTW
const handleChangeName = e => setstate({
...state,
Name: e.target.value
});
If you are sticking to the array state, the listener should look something like this instead.
const handleChangeName = e => setstate([
...state,
{
...state[0], // or whatever index you may use in the future
Name: e.target.value
}
]);

You can do the following assignment state.Name=e.target.value ****:
You are using an array not an object, so there is nothing you can access using state.Name=e.target.value
So if wanna access it directly the same way you used you have to use state property as OBJECT not as ARRAY:
const iState = {
Name: '',
Email: '',
Salary: 0
}
And the standard for the component that has form to handle is to use stateful component
OR
You can use stateless (functional) component and make form each form field its own state:
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [salary, setSalary] = useState(0);
So the component will be:
import React, { useState } from 'react'
function ReactForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [salary, setSalary] = useState(0)
function validationHandler() {
console.log('Name: ' + name);
console.log('Email: ' + email);
console.log('Salary: ' + salary);
}
return (
<div>
Name : <input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}></input>
<br></br>
Email : <input
type="text"
value={email}
onChange={(e) => setEmail(e.target.value)}></input>
<br></br>
Salary : <input
type="text"
value={salary}
onChange={(e) => setSalary(e.target.value)}></input>
<br></br>
<button onClick={validationHandler}>Validate Us</button>
</div>
)
}
export default ReactForm;

Related

Setting State From props Values To Make An UPDATE Request

I have Project objects:
{
id: "",
projectName: "" ,
projectIdentifier: "" ,
description:"" ,
startDate: Date ,
endDate: Date ,
}
I have a component that gets called when a user clicks on an "Update Project" button. The specific Project that they clicked on gets passed into the UpdateProject component via props.
When I try to console.log(props.project) right below the const updateProject = (props) => { line, I can see the object coming in. Great. :-)
{
id: 3,
projectName: "Name" ,
projectIdentifier: "1234" ,
description:"Project description" ,
startDate: "02-11-2022" ,
endDate: "02-11-2022" ,
}
However, I am having trouble setting the state in this component. I need to be able to update the details of the Project object and send that UPDATE request to the server.
Any help is greatly appreciated.
import React, { useState, useEffect, useRef } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { useNavigate, useParams } from "react-router";
import { getProject, createProject } from "../../actions/projectActions";
const UpdateProject = (props) => {
console.log(props.project); //the Project object is coming in!!!
let navigate = useNavigate();
const { id } = useParams();
const [projectName, setProjectName] = useState(props.project.projectName);
console.log(props.project.projectName); <---- this is defined in console.log :-)
console.log(projectName); <---- this is "undefined"
const [projectIdentifier, setProjectIdentifier] = useState(
props.project.projectIdentifier
);
const [description, setDescription] = useState(props.project.description);
const [startDate, setStartDate] = useState(props.project.startDate);
const [endDate, setEndDate] = useState(props.project.endDate);
const [errors, setErrors] = useState(props.project.errors);
const [state, setState] = useState({
id,
projectName: props.project.projectName,
projectIdentifier: props.project.projectIdentifier,
description: props.project.description,
startDate: props.project.startDate,
endDate: props.project.endDate,
});
console.log("state before useEffect: ", state); // <--- here, id is the only thing console logging. Every other key is returning 'undefined'
useEffect(() => {
if (props.errors) {
setErrors(props.errors);
}
props.onGetProject(id, navigate);
console.log("STATE: ", state); <--- again, id is the only thing console logging. Every other key is returning 'undefined'
}, [props.errors]);
const onSubmit = (e) => {
e.preventDefault();
const updateProject = {
id: this.state.id,
projectName: this.state.projectName,
projectIdentifier: this.state.projectIdentifier,
description: this.state.description,
startDate: this.state.startDate,
endDate: this.state.endDate,
errors: {},
};
props.onCreateProject(updateProject, navigate);
};
For the rest of the component, my inputs in the return() method look like this, for example:
<form onSubmit={onSubmit}>
<div className="form-group">
<input
type="text"
className={classNames("form-control form-control-lg ", {
"is-invalid": errors.projectName,
})}
placeholder="Project Name"
name="projectName"
defaultValue={props.project.projectName}
onChange={(e) => setProjectName(e.target.value)}
/>
{errors.projectName && (
<div className="invalid-feedback">{errors.projectName}</div>
)}
</div>
It's anti-pattern to store passed props into local component state, just consume the prop value directly. You are also incorrectly referencing a this in the submit handler. this is OFC simply undefined in function components.
From what I can tell you are wanting to initialize the projectName from props, update this value in a form, and upon submitting the form, use this projectName state along with the project object passed as props to update a project.
Use an useEffect hook to keep the local state synchronized with the project object if/when the props.project updates.
const [projectName, setProjectName] = useState(props.project.projectName);
useEffect(() => {
setProjectName(props.project.projectName);
}, [props.project.projectName]);
Merge this projectName state with the props.project object in the submit handler.
const onSubmit = (e) => {
e.preventDefault();
const updateProject = {
...props.project, // <-- shallow copy props.project object
id, // <-- id from params
projectName, // <-- projectName state
errors: {},
};
props.onCreateProject(updateProject, navigate);
};
The form should use a controlled input, using the projectName state as the value.
<form onSubmit={onSubmit}>
<div className="form-group">
<input
type="text"
className={classNames(
"form-control form-control-lg ",
{ "is-invalid": errors.projectName }
)}
placeholder="Project Name"
name="projectName"
value={projectName}
onChange={(e) => setProjectName(e.target.value)}
/>
{errors.projectName && (
<div className="invalid-feedback">{errors.projectName}</div>
)}
</div>
</form>
Update
Since you are attempting to convert a class component to a function component, here are some basic steps:
Convert class to function and body, change render method to be the function return.
Convert component state into a useState hook.
Convert the componentDidMount, componentDidUpdate, and componentWillUnmount lifecycle methods into one or more useEffect hooks with appropriate dependency array.
Convert all references to this.state to the new state variables, and this.props to props or any variables destructured from props.
Class component being converted
Function component version:
const UpdateProject = ({ createProject, getProject, project }) => {
const navigate = useNavigate();
const { id } = useParams();
const [state, setState] = useState({
id: "",
projectName: "",
projectIdentifier: "",
description: "",
startDate: "",
endDate: ""
});
useEffect(() => {
setState(project); // update project state when project prop updates
}, [project]);
useEffect(() => {
getProject(id, navigate); // fetch project when id updates
}, [id]);
const onChange = (e) => {
setState((state) => ({
...state,
[e.target.name]: e.target.value
}));
};
const onSubmit = (e) => {
e.preventDefault();
const updateProject = {
...state
};
createProject(updateProject, navigate);
};
return (
<div className="project">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<h5 className="display-4 text-center">Update Project form</h5>
<hr />
<form onSubmit={onSubmit}>
<div className="form-group">
<input
type="text"
className="form-control form-control-lg "
placeholder="Project Name"
name="projectName"
value={state.projectName}
onChange={onChange}
/>
</div>
<div className="form-group">
<input
type="text"
className="form-control form-control-lg"
placeholder="Unique Project ID"
name="projectIdentifier"
value={state.projectIdentifier}
onChange={onChange}
disabled
/>
</div>
<div className="form-group">
<textarea
className="form-control form-control-lg"
placeholder="Project Description"
name="description"
onChange={onChange}
value={state.description}
/>
</div>
<h6>Start Date</h6>
<div className="form-group">
<input
type="date"
className="form-control form-control-lg"
name="startDate"
value={state.startDate}
onChange={onChange}
/>
</div>
<h6>Estimated End Date</h6>
<div className="form-group">
<input
type="date"
className="form-control form-control-lg"
name="endDate"
value={state.endDate}
onChange={onChange}
/>
</div>
<input type="submit" className="btn btn-primary btn-block mt-4" />
</form>
</div>
</div>
</div>
</div>
);
};
Adding Redux
While you could still use the connect Higher Order Component from react-redux it's more common now to use the useDispatch and useSelector hooks.
import { useDispatch, useSelector } from 'react-redux';
const UpdateProject = ({ createProject, getProject, project }) => {
...
const dispatch = useDispatch();
const project = useSelector(state => state.project.project);
...
useEffect(() => {
dispatch(getProject(id, navigate)); // fetch project when id updates
}, [id]);
...
const onSubmit = (e) => {
e.preventDefault();
const updateProject = {
...state
};
dispatch(createProject(updateProject, navigate));
};
...

React Hooks: handle multiple inputs

on react docs forms section there is the following example using class components:
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
<form>
<label>
Is going:
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Number of guests:
<input
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
</form>
);
}
}
Considering Hooks can only be called either in a React function component or a custom React Hook function is there a way of doing it using hooks instead?
you can clean up #adam 's final solution a bit by not using the useCallback hook, and instead simply using the useState hook as a controlled component.
const MyComponent = () => {
const [inputs, setInputs] = useState({});
const handleChange = e => setInputs(prevState => ({ ...prevState, [e.target.name]: e.target.value }));
return (
<>
<input name="field1" value={inputs.field1 || ''} onChange={handleChange} />
<input name="field2" value={inputs.field2 || ''} onChange={handleChange} />
</>
)
}
example
const MyComponent = () => {
const [inputs,setInputs] = useState({});
return (
<>
<input key="field1" name="field1" onChange={({target}) => setInputs(state => ({...state,field1:target.value}))} value={inputs.field1}/>
<input key="field2" name="field2" onChange={({target}) => setInputs(state => ({...state,field2:target.value}))} value={inputs.field2}/>
</>
)
}
you can pass in initial values like this:
const MyComponent = (initialValues = {}) => {
const [inputs,setInputs] = useState(initialValues);
...
}
EDIT: A nice short onChange according to #hamidreza's comment
const MyComponent = (initialValues = {}) => {
const [inputs,setInputs] = useState(initialValues);
const onChangeHandler = useCallback(
({target:{name,value}}) => setInputs(state => ({ ...state, [name]:value }), [])
);
return (
<>
<input key="field1" name="field1" onChange={onChangeHandler} value={inputs.field1}/>
<input key="field2" name="field2" onChange={onChangeHandler} value={inputs.field2}/>
</>
)
}
etc, etc, etc
Maybe, on the last example onChangeForField('...') will be triggered on each render, so maybe you have to write onChange={()=>onChangeForField('...')} or if you want the event to get passed onChange={(e)=>onChangeForField('...', e)}
I was looking for the same answer,but i was finding difficulty to understand the previous solutions,so i tried in my own way ,and i found a solution.
const [inputs,setInputs] = useState({
'field1':'',
'field2':'',
});
const handleChange = (e) => {
const name = e.target.name; //it is the name of that input
const value = e.target.value; //value of that input
setInputs((prev) => {
prev[name] = value;//changing the updated value to the previous state
return prev;
});
};
return (
<>
<input key="field1" name="field1" onChange={handleChange} value={inputs.field1}/>
<input key="field2" name="field2" onChange={handleChange} value={inputs.field2}/>
</>
adding to Adam's answer and for those who are looking towards typescript solution,
interface MyIType {
field1: string;
...
}
//Partial from typescript to make properties optional
interface MyFormType extends Partial<MyIType> {}
const [inputs,setInputs] = useState<MyFormType>(initialValues);
const onChangeForField = useCallback(({target}) =>
setInputs(_state => {
return {
..._state,
[target.name]: target.value,
};
}),
[]
);
If you were like me, having multiple inputs on multiple pages using the same input id/name/key, try value={data.xxx || ''} .
Full code:
const [data, setData] = useState<any>({});
const handleValueChanges = e => {
setData({
...data,
[e.target.name]: e.target.value,
});
};
<InputText (using prime react)
id="firstName"
name="firstName"
value={data.firstName || ''}
onChange={handleUpdate}
/>
As of v6 you can use .forEach(), Please refer to the migrate guide
[{name: "firstName", value: "Safwat" }, {name: "lastName", value: "Fathi", }].forEach(({name, value}) => setValue(name, value));

React redux -- input field not letting me type

So I have 3 input fields, one for name, email and password. The email and password input field are working fine, but the name input field is not letting me type anything. I have the values for the input fields set to come from user, so it auto-fills the fields. Here is my code
import React, {useState, useEffect} from 'react';
import {useParams} from 'react-router-dom';
import {connect} from 'react-redux';
import {editUserData, fetchUserData, deleteProfile} from '../actions/index';
const EditUser = props => {
const [user, setUser] = useState({name: '', email: '', password: ''})
const params = useParams();
const editUser = e => {
e.preventDefault();
props.editUserData(params, user);
}
const handleChanges = e => {
e.persist();
setUser({...user, [e.target.name]: e.target.value});
}
useEffect(() => {
props.fetchUserData(params, setUser);
}, [])
const deleteOnClick = () => {
props.deleteProfile(params)
}
return (
<>
<form className='editUserForm' onSubmit={editUser}>
<h3>Edit Profile !</h3>
<div>Name</div>
<input className='editInput' type='text' name='name' value={`${user.firstName} ${user.lastName}`} onChange={handleChanges} />
<div>Email</div>
<input className='editInput' type='text' name='email' value={user.email} onChange={handleChanges} />
<div>Password</div>
<input className='editInput' type='text' name='password' value={user.password} onChange={handleChanges} />
<button className='submitButton'>Submit</button>
</form>
<div className='deleteProfile'>
<button className='deleteProfileButton' onClick={deleteOnClick}>Delete Profile</button>
</div>
</>
)
}
const mapStateToProps = state => {
return {
users: [],
user: {},
registerSuccessMessage: '',
user_stories: {},
isLoading: false,
error: null
}
}
export default connect(mapStateToProps, {editUserData, fetchUserData, deleteProfile})(EditUser);
Edit (after the suggestion of #Boussadjra)
This is what state looks like after props.fetchUserData. -- where setUser is --
That is why I have input values to ${user.firstName} ${user.lastName}
That's because you are setting the "name" input's value to ${user.firstName} ${user.lastName}, which are undefined. You could set your user state to initially have these properties, but I would suggest using separate useState()'s for each of firstName, lastName, email, and password (since combining first and last names in a single input is prone to errors, as mentioned in the comments):
import React, {useState, useEffect} from 'react';
import {useParams} from 'react-router-dom';
import {connect} from 'react-redux';
import {editUserData, fetchUserData, deleteProfile} from '../actions/index';
const EditUser = props => {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const params = useParams();
const editUser = e => {
e.preventDefault();
props.editUserData(params, user);
}
useEffect(() => {
props.fetchUserData(params, setUser);
}, [])
const deleteOnClick = () => {
props.deleteProfile(params)
}
return (
<>
<form className='editUserForm' onSubmit={editUser}>
<h3>Edit Profile !</h3>
<div>First Name</div>
<input className='editInput' type='text' name='firstName' value={firstName} onChange={e => setFirstName(e.target.value)} />
<div>Last Name</div>
<input className='editInput' type='text' name='lastName' value={lastName} onChange={e => setLastName(e.target.value)} />
<div>Email</div>
<input className='editInput' type='text' name='email' value={email} onChange={e => setEmail(e.target.value)} />
<div>Password</div>
<input className='editInput' type='text' name='password' value={password} onChange={e => setPassword(e.target.value)} />
<button className='submitButton'>Submit</button>
</form>
<div className='deleteProfile'>
<button className='deleteProfileButton' onClick={deleteOnClick}>Delete Profile</button>
</div>
</>
)
}
const mapStateToProps = state => {
return {
users: [],
user: {},
registerSuccessMessage: '',
user_stories: {},
isLoading: false,
error: null
}
}
export default connect(mapStateToProps, {editUserData, fetchUserData, deleteProfile})(EditUser);
user.firstName and user.lastName are undefined they are not defined as properties in your user state, so you should simply use the firstName and lastName properties as value :
value={ us}
or define your state as follows :
const [user, setUser] = useState({firstName:'',lastName:'', email: '', password: ''})
we suppose that the first and the last name are separated by space so when you come to update the state split that name :
const handleChanges = e => {
e.persist();
if(e.target.name==='name'){
let name=e.target.value.split(' ')
setUser({...user, firstName:name[0],lastName:name[1]});
}else{
setUser({...user, [e.target.name]: e.target.value});
}
}

React hooks: Can't update state inside function component

I'm new to React and am trying to figure out how to make a phonebook. I've gotten quite far but I'm having an issue I can't solve. I'm using React Hooks.
Everything works fine, except for when I call the setNewNumber('') and setNewName('') functions at the end of addPerson(), just before the filteredEntries const.
I want to reset the input fields in the form to empty strings ('') once the other code inside addPerson() is done running, but it seems like the two functions are never called since the value for newName and newNumber don't change to '' (instead they keep the values the user added). However, my other useState functions (setPersons() and setFilteredPersons()) work inside addPerson()...
I've tried reading the documentation and asking around but haven't found a solution. I'd be very grateful for any clues/help!
import React, { useState } from 'react'
import Person from './components/Person'
const App = () => {
const [ persons, setPersons ] = useState([
{ name: 'Cat', number: '111' },
{ name: 'Dog', number: '222' },
{ name: 'Horse', number: '333' },
{ name: 'Owl', number: '444' }
])
const [filteredPersons, setFilteredPersons] = useState([...persons])
const [ newName, setNewName ] = useState('')
const [ newNumber, setNewNumber ] = useState('')
const addPerson = (event) => {
event.preventDefault()
const createPerson = () => {
const personObject = {
name: newName,
number: newNumber,
}
setPersons([...persons, personObject])
setFilteredPersons([...persons, personObject]) //varför går det inte att bara köra [...persons?]
}
const upperCaseNewName = newName.toUpperCase()
let doubleName
persons.map(person => {
const upperCasePerson = person.name.toUpperCase()
if(upperCaseNewName === upperCasePerson) {
doubleName = upperCasePerson
}
return doubleName
})
if (doubleName === undefined) {
createPerson()
} else if(doubleName === upperCaseNewName) {
alert(`${newName} is already in the phonebook`)
}
setNewName('')
setNewNumber('')
}
const filterEntries = event => {
let filtered = persons.filter(person => {
return person.name.toUpperCase().indexOf(event.target.value.toUpperCase()) !== -1
})
setFilteredPersons(filtered)
}
const renderPersons = () => filteredPersons.map(person =>
<Person key={person.name} name={person.name} number={person.number}/>
)
return (
<div>
<h2>Phonebook</h2>
<p>Filter entries:</p> <input onChange={(event) => filterEntries(event)}/>
<form>
<div>
name: <input onChange={(event) => setNewName(event.target.value)}/>
<br/>
phone: <input onChange={(event) => setNewNumber(event.target.value)}/>
</div>
<div>
<button type="submit" onClick={addPerson}>add</button>
</div>
</form>
<h2>Numbers</h2>
{renderPersons()}
</div>
)
}
export default App
The person component at the top just contains this code:
import React from 'react'
const Person = (props) => {
return(
<>
<p>{props.name} {props.number}</p>
</>
)
}
export default Person
Your components are not actually tied to your state values. You need them to be "controlled." Check out the docs for more examples :)
https://reactjs.org/docs/forms.html#controlled-components
<input value={newName} onChange={event => setNewName(event.target.value)} />
The reset is working correctly. What you forgot to do is add the value to each input. Without the value attribute the input is considered an uncontrolled component. By the sounds of it, you're looking to control the value via code.
Change
<div>
name: <input onChange={event => setNewName(event.target.value)} />
<br />
phone: <input onChange={event => setNewNumber(event.target.value)} />
</div>
to
<div>
name: <input value={newName} onChange={event => setNewName(event.target.value)} />
<br />
phone: <input value={newNumber} onChange={event => setNewNumber(event.target.value)} />
</div>
Codesandbox Demo
You have missed adding value attribute to input and thus your component is not the "Controlled" component.
You can read more here.
Changes needed
<input
value={newName}
onChange={event => setNewName(event.target.value)}
/>
<br />
phone:
<input
value={newNumber}
onChange={event => setNewNumber(event.target.value)}
/>
Codesandbox Link: https://codesandbox.io/s/crimson-frog-ecp98
Hope this Helps!

Using Dynamic Var with `Set` State in React Hooks?

This is a pretty common pattern in React components:
handleTextFieldChange(event)
{
const name = event.currentTarget.name;
this.setState({[name]: event.currentTarget.value})
}
What Javascript syntax could be used to do the same with React hooks?
i.e. something possibly along the lines of:
handleTextFieldChange(event)
{
const name = event.currentTarget.name;
this.set[name](event.currentTarget.value);
}
You could use a single useState with a default value of an object that contains all your input values and update that like you are used to with class components.
Example
const { useState } = React;
function App() {
const [state, setState] = useState({ email: "", password: "" });
function onChange(event) {
const { name, value } = event.target;
setState(prevState => ({ ...prevState, [name]: value }));
}
return (
<div>
<input value={state.email} name="email" onChange={onChange} />
<input value={state.password} name="password" onChange={onChange} />
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
How about something like this?
function handleTextFieldChange(mySetFunction, event) {
const value = event.currentTarget.value;
mySetFunction(value);
}
<TextField
placeholder="Email"
name="passwordResetEmailAddress"
onChange={(e) => handleTextFieldChange(setPasswordResetEmailAddress, e)}
>
{passwordResetEmailAddress}
</TextField>
I've tested it and it works.
class Yup extends React.Component {
state = {
first: "",
second: ""
};
handleTextFieldChange = ({ target: { name, value } }) =>
this.setState({ [name]: value });
render() {
const { first, second } = this.state;
return (
<div>
<p>{first}</p>
<p>{second}</p>
<input type="text" name="first" onChange={this.handleTextFieldChange} />
<input
type="text"
name="second"
onChange={this.handleTextFieldChange}
/>
</div>
);
}
}
same with hook
function Yup() {
const [{ first, second }, setState] = useState({ first: "", second: "" });
function handleTextFieldChange({ target: { name, value } }) {
setState(prevState => ({ ...prevState, [name]: value }));
}
return (
<div>
<p>{first}</p>
<p>{second}</p>
<input type="text" name="first" onChange={handleTextFieldChange} />
<input type="text" name="second" onChange={handleTextFieldChange} />
</div>
);
}
You can dynamically update a state for the target field by receiving an update state function as an argument in onChange function.
Example
import React, { useState } from "react";
const App = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const onChangeHandler = (setIdentifierState, event) => {
setIdentifierState(event.target.value);
};
return (
<div>
<p>{"Email: " + email}</p>
<p>{"Password: " + password}</p>
<input
type="text"
placeholder="email"
onChange={onChangeHandler.bind(null, setEmail)}
/>
<input
type="text"
placeholder="password"
onChange={onChangeHandler.bind(null, setPassword)}
/>
</div>
);
};
export default App;
I recently tackled this same problem while converting my components from classes to functions. I ended up creating an object that could then point to the separate state hooks:
const textStates = {};
const setTextStates= {};
for (var name of names) {
let [textState, setTextState] = useState("");
textStates[name] = textState;
setTextStates[name] = setTextState;
}
I solved it this way (a slightly more dynamic solution than what #VikR offered)
const [title, setTitle] = useState("");
const [desc, setDesc] = useState("");
const [video, setVideo] = useState("");
const handleChange = setter => event => {
const value = event.target.value;
//special cases
if (setter === setVideo) {
setInvalidVideo(!ReactPlayer.canPlay(value))
}
setter(value)
}
Then in my code:
<TextField fullWidth value={title} type="date"
label={t('service.ticket.add.title')}
placeholder={t('service.ticket.add.titlePh')}
onChange={handleChange(setTitle)} variant="outlined"/>

Categories

Resources