Reputation: 9662
I need to maintain array of objects which is stored in a state object. Basically I need to push each object to this array whenever I click on Add button .This should basically store this object in array.
Also I am unable to fetch proper values when I am trying to submit? Where am I going wrong?
Basically the structure I want is:
users= [
{"name":"xxx","email":"yyy","phone":"656"},
{"name":"yyy","email":"xxx","phone":"55"}
];
import * as React from 'react';
interface IState{
users : Account[];
}
interface Account{
name: string;
email: string;
phone: string
}
export default class App extends React.Component<{},IState> {
constructor(props:any){
super(props);
this.state= {
users: []
}
}
handleChange = ( event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({
users:{
...this.state.users,
[event.target.name]:event.target.value
}
})
}
onAdd = () => {
this.setState((prevState) => ({
users: [...prevState.users],
}));
console.log(this.state.users); // Unable to get the proper info
}
render(){
<React.Fragment>
<form onSubmit={this.onAdd}>
<input type="text" onChange={(e:any) => this.handleChange(e)} name={"name"} />
<input type="text" onChange={(e:any) => this.handleChange(e)} name={"email"} />
<input type="text" onChange={(e:any) => this.handleChange(e)} name={"phone"} />
<button type="submit">Add</button>
</form>
</React.Fragment>
}
}
Upvotes: 1
Views: 4049
Reputation: 11257
Things to correct:-
1) You are using only one state variable users
for one user as well as all users. So create two state variables, one for temporary storing of data for a user and users
variable for storing all users data.
2) You are trying to access console.log(this.state.users);
after setState but it is not in the callback, setState is asynchronous it should be in callback of setState.
3) When user submits the form, the page refreshes which is default behaviour of application, we need e.preventDefault();
to override this behaviour.
4) Use state for individual input textboxes so that you could may be apply validation etc on fields.
import * as React from "react";
import { render } from "react-dom";
interface IState {
users : Account[],
user: Account
}
interface Account{
name: string;
email: string;
phone: string
}
class App extends React.Component<{}, IState> {
constructor(props: any) {
super(props);
this.state = {
users: [],
user: {name: '', email:'', phone: ''}
}
}
handleChange = (event: React.FormEvent<HTMLInputElement>) => {
this.setState({
user: {
...this.state.user,
[event.currentTarget.name]: event.currentTarget.value
}
});
};
onAdd = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
this.setState(
{
users: [...this.state.users, this.state.user],
user: {name:'', email: '', phone: ''}
},
() => {
console.log("updated state", this.state.users);
}
);
};
public render() {
const { name, email, phone } = this.state.user;
return (
<form onSubmit={this.onAdd}>
<input type="text" onChange={this.handleChange} value={name} name="name" />
<input type="text" onChange={this.handleChange} value={email} name="email" />
<input type="text" onChange={this.handleChange} value={phone} name="phone" />
<button type="submit">Add</button>
</form>
);
}
}
render(<App />, document.getElementById("root"));
Improvement Area - You could declare array of fields like fields = ['name', 'phone', 'email'] and map over in render function, this way you would need to write form once and any no of fields could be added.
Hope that helps!!!
Upvotes: 1
Reputation: 2106
you don't need handleChange, in onAdd get all inputs value from the event, put them in object( like {name: event.target.form.elements.name.value ...} and set it in users(which will be an array)
export default class App extends React.Component{
constructor(props:any){
super(props);
this.state = {
users: []
}
}
onAdd = (event) => {
const user = {
name: event.target.form.elements.name.value,
email: event.target.form.elements.email.value,
phone: event.target.form.elements.phone.value
}
this.setState({
users: [...this.state.users, user]
});
}
render(){
<React.Fragment>
<form onSubmit={this.onAdd}>
<input type="text" name="name" />
<input type="text" name="email" />
<input type="text" name="phone" />
<button type="submit">Add</button>
</form>
</React.Fragment>
}
}
then if you log this.state.users you will get the stractue you need
users= [
{"name":"xxx","email":"yyy","phone":"656"},
{"name":"yyy","email":"xxx","phone":"55"}
];
Upvotes: 1
Reputation: 2212
export default class App extends React.Component<{},IState> {
state = {
users: [],
text: '',
}
handleChange = ( event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({
[e.target.name]: e.target.value
})
}
onAdd = () => this.setState({
users:[
...this.state.users,
{
e.target.name: e.target.value,
e.target.email: e.target.value,
e.target.phone: e.target.value
}
]
})
render(){
<React.Fragment>
<form onSubmit={this.onAdd}>
<input type="text" onChange={(e:any) => this.handleChange(e)} name={"name"} />
<input type="text" onChange={(e:any) => this.handleChange(e)} name={"email"} />
<input type="text" onChange={(e:any) => this.handleChange(e)} name={"phone"} />
<button type="submit">Add</button>
</form>
</React.Fragment>
}
}
You are setting your users
as an array and then you are converting it into an object with the handleChange
. Try to see if this works
Upvotes: -1
Reputation: 2385
Update onAdd
like below, because setState
method updates state asynchronously, therefore you can't get the state right after calling it, but you can do so using a callback as second argument in setState
method which is invoked after the method has updated the state
onAdd = () => {
this.setState((prevState) => {
const newUser = {}
return {
users: [...prevState.users, newUser],
}
}, () => {
console.log(this.state.users)
});
}
Upvotes: 2