Handling Inputs, Rendering Lists, and Form Submission in React
- To render lists in React, use the
map
function to iterate over an array of items and return a component for each item.<ul> {tasks.map((task) => { return <li key={task.id}>{task.text}</li>; })} </ul>
- When rendering lists, make sure to assign a unique
key
prop to each component. Thekey
helps React efficiently update and re-render components when the list changes.{tasks.map((task) => { return <li key={task.id}>{task.text}</li>; })}
- To handle input fields and forms in React, use event handlers and state management.
<input onChange={handleChange} value={task.text} type="text" id="taskInput" />
- For form submission, use the
onSubmit
event on the<form>
element. Prevent the default form behavior usinge.preventDefault()
to avoid page refresh.<form onSubmit={onSubmitTask}> <input onChange={handleChange} value={task.text} type="text" id="taskInput" /> <button type="submit">Add Task</button> </form>
- Use the
concat
or spread operator to update arrays in state. Avoid directly modifying state arrays or using thepush
method, as it can lead to errors and incorrect rendering.this.setState({ tasks: this.state.tasks.concat(this.state.task), task: { text: "" }, });
- When rendering components, pass data as props to child components. This allows child components to access and display the data.
<Overview tasks={tasks} />
- Remember to import necessary modules, such as
React
,Component
, and any additional packages or components used in your code.import React, { Component } from "react";
Complete code:
// Overview.js
import React from "react";
const Overview = (props) => {
const { tasks } = props;
return (
<ul>
{tasks.map((task) => {
return <li key={task.id}>{task.text}</li>;
})}
</ul>
);
};
export default Overview;
// App.js
import React, { Component } from "react";
import Overview from "./components/Overview";
import uniqid from "uniqid";
class App extends Component {
constructor() {
super();
this.state = {
task: {
text: '',
id: uniqid()
},
tasks: [],
};
}
handleChange = (e) => {
this.setState({
task: {
text: e.target.value,
id: this.state.task.id,
},
});
};
onSubmitTask = (e) => {
e.preventDefault();
this.setState({
tasks: this.state.tasks.concat(this.state.task),
task: {
text: '',
id: uniqid()
},
});
};
render() {
const { task, tasks } = this.state;
return (
<div>
<form onSubmit={this.onSubmitTask}>
<label htmlFor="taskInput">Enter task</label>
<input
onChange={this.handleChange}
value={task.text}
type="text"
id="taskInput"
/>
<button type="submit">Add Task</button>
</form>
<Overview tasks={tasks} />
</div>
);
}
}
export default App;
Displaying Task Numbers
- Modify the
Overview
component code inOverview.js
. - Add the
index
parameter in themap
function callback. - Use
index + 1
to display the task number in the list item.
// Overview.js
import React from "react";
const Overview = (props) => {
const { tasks } = props;
return (
<ul>
{tasks.map((task, index) => {
return <li key={task.id}>{`Task ${index + 1}: ${task.text}`}</li>;
})}
</ul>
);
};
export default Overview;
Editing Tasks
- Modify the
Overview
component code inOverview.js
. - Add the
handleEditTask
andhandleDeleteTask
props. - Add edit and delete buttons for each task.
- Add
onClick
event handlers to the edit and delete buttons, calling the respective functions with the task as the argument.
// Overview.js
import React from "react";
const Overview = (props) => {
const { tasks, handleEditTask, handleDeleteTask } = props;
return (
<ul>
{tasks.map((task) => {
return (
<li key={task.id}>
<span>{task.text}</span>
<button onClick={() => handleEditTask(task)}>Edit</button>
<button onClick={() => handleDeleteTask(task)}>Delete</button>
</li>
);
})}
</ul>
);
};
export default Overview;
- Modify the
App
component code inApp.js
. - Import the
Overview
component anduniqid
package. - Add the
editingTaskId
state variable to track the currently edited task. - Create the
handleEditTask
function to set the task andeditingTaskId
in state. - Create the
handleDeleteTask
function to remove the task from state. - Modify the
onSubmitTask
function to handle both adding a new task and updating an existing task. - Update the render method to pass the necessary props to the
Overview
component.
// App.js
import React, { Component } from "react";
import Overview from "./components/Overview";
import uniqid from "uniqid";
class App extends Component {
constructor() {
super();
this.state = {
task: {
text: "",
id: uniqid(),
},
tasks: [],
editingTaskId: null,
};
}
handleChange = (e) => {
this.setState({
task: {
text: e.target.value,
id: this.state.task.id,
},
});
};
onSubmitTask = (e) => {
e.preventDefault();
const { tasks, task, editingTaskId } = this.state;
if (editingTaskId) {
// Update existing task
const updatedTasks = tasks.map((t) => {
if (t.id === editingTaskId) {
return { ...t, text: task.text };
}
return t;
});
this.setState({
tasks: updatedTasks,
task: { text: "", id: uniqid() },
editingTaskId: null,
});
} else {
// Add new task
this.setState({
tasks: tasks.concat(task),
task: { text: "", id: uniqid() },
});
}
};
handleEditTask = (task) => {
this.setState({
task: { text: task.text, id: task.id },
editingTaskId: task.id,
});
};
handleDeleteTask = (task) => {
const { tasks } = this.state;
const updatedTasks = tasks.filter((t) => t.id !== task.id);
this.setState({ tasks: updatedTasks });
};
render() {
const { task, tasks } = this.state;
return (
<div>
<form onSubmit={this.onSubmitTask}>
<label htmlFor="taskInput">Enter task</label>
<input
onChange={this.handleChange}
value={task.text}
type="text"
id="taskInput"
/>
<button type="submit">Add Task</button>
</form>
<Overview
tasks={tasks}
handleEditTask={this.handleEditTask}
handleDeleteTask={this.handleDeleteTask}
/>
</div>
);
}
}
export default App;