Reputation: 25
Two part question here: First, can anyone explain to me why this.state.taskName and this.state.taskBody and their corresponding inputs aren't clearing after submitting the form? In handleSubmit() I'm using this.setState() to set their states to an empty string, but it doesn't seem to be working. It also wont let me submit more than once, which I suspect might have to do with the state not clearing.
Second, what would be the best way to push a task with multiple key-value pairs into the this.state.tasks array? I tried storing taskName and taskBody as an object in state, and also tried pushing the them into an object and then displaying them, but couldn't get it to work.
Here are parent, child, & sibling files:
import React, { Component } from 'react';
import Task from './Task/Task';
import NewTaskForm from './NewTaskForm/NewTaskForm';
class Board extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
this.state = {
tasks: [],
taskName: '',
taskBody: ''
};
}
handleSubmit(e) {
e.preventDefault();
let updatedTasks = this.state.tasks;
let taskName = this.state.taskName;
let taskBody = this.state.taskBody;
updatedTasks.push(taskName, taskBody);
let updatedName = '';
let updatedBody = '';
this.setState({ tasks: updatedTasks, taskName: updatedName, taskBody: updatedBody });
};
handleChange(e) {
this.setState({ [e.name]: e.value });
}
render() {
return (
<div>
<NewTaskForm
onSubmit={this.handleSubmit}
onChange={this.handleChange}
/>
<Task
tasks={this.state.tasks}
/>
</div>
);
}
}
export default Board;
import React, { Component } from 'react';
class NewTaskForm extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.onChange(e.target);
}
render() {
return (
<form onSubmit={this.props.onSubmit}>
<label>Task Name</label>
<input
name="taskName"
required type="text"
value={this.props.taskName}
onChange={this.handleChange}
placeholder="Enter a task name"
/>
<label>Task Body</label>
<input
name="taskBody"
required type="text"
value={this.props.taskBody}
onChange={this.handleChange}
placeholder="Enter a task body"
/>
<button
type="submit"
className="btn btn-default"
>Add Task
</button>
</form>
);
}
}
export default NewTaskForm;
import React, { Component } from 'react';
class Task extends Component {
render() {
let taskList = this.props.tasks.map((task, i) => {
return (
<li key={i}>
{task}
</li>
);
});
return (
<ul>
{taskList}
</ul>
)
}
}
export default Task;
Thanks!
Upvotes: 0
Views: 1450
Reputation: 358
Please see your altered code below. Ive added explanations beneath for the main alterations I've made :)
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
tasks: [],
taskName: '',
taskBody: ''
};
}
handleSubmit(e) {
e.preventDefault();
let tasks = this.state.tasks;
let taskName = this.state.taskName;
let taskBody = this.state.taskBody;
tasks.push({taskName, taskBody});
this.setState({tasks, taskName: '', taskBody: ''});
};
handleChange(e) {
const name = e.target.name;
const value = e.target.value;
this.setState({[name]: value});
}
render() {
return (
<div>
<NewTaskForm
taskName={this.state.taskName}
taskBody={this.state.taskBody}
onSubmit={(e) => this.handleSubmit(e)}
onChange={(e) => this.handleChange(e)}
/>
<Tasks
tasks={this.state.tasks}
/>
</div>
);
}
}
class NewTaskForm extends React.Component {
render() {
return (
<form onSubmit={this.props.onSubmit}>
<label>Task Name</label>
<input
name="taskName"
required type="text"
value={this.props.taskName}
onChange={(e) => this.props.onChange(e)}
placeholder="Enter a task name"
/>
<label>Task Body</label>
<input
name="taskBody"
required type="text"
value={this.props.taskBody}
onChange={(e) => this.props.onChange(e)}
placeholder="Enter a task body"
/>
<button type="submit" className="btn btn-default">Add Task</button>
</form>
);
}
}
class Tasks extends React.Component {
render() {
let taskList = this.props.tasks.map((task, i) => {
return (
<li key={i}>
<b>{task.taskName}</b><br/>
{task.taskBody}
</li>
);
});
return (
<ul>
{taskList}
</ul>
)
}
}
Working fiddle: https://jsfiddle.net/8sLw4phf/2/
Upvotes: 2
Reputation: 55740
I can see couple of issues with the way you have written the code. For starters, you are not passing in taskName
and taskBody
as props to NewTaskForm
, as the component expects the value to be read from the props.
Check this code snippet - https://codesandbox.io/s/ov675m6r7y
Upvotes: 1
Reputation: 324
I would try something like this:
handleSubmit(e) {
e.preventDefault();
const { taskName, taskBody } = this.state;
this.setState({
tasks: [...this.state.tasks, { taskName, taskBody }]
taskName: '',
taskBody: ''
});
};
This way you are not mutating your state and your array contains one object per task.
Upvotes: 0
Reputation: 401
To address your first question, the reason the inputs aren't clearing is because you are not passing the taskName
and taskBody
values as props to <NewTaskForm />
. The inputs aren't being controlled by React since NewTaskForm
isn't receiving them, so they are currently entirely user-controlled. Add them and you'll see them clear after submitting the form.
The best way to hold a taskName
/taskBody
pair in state is as you said: an object. In your TaskComponent
you'll need to change the mapping logic to work with an object, though, as well as make sure you push an object to this.state.tasks
in Board
. I've linked to a Fiddle that shows the changes I made: https://jsfiddle.net/0z89Lcpw/.
Specifically the changes I made versus your code are:
{taskName, taskBody}
taskName
and taskBody
props to NewTaskForm
taskName
and taskBody
off of each task and present both--of course you can present these pieces of data in quite a few different ways to suit your presentational purposes.Upvotes: 3