Reputation:
I'm learning React Redux and i'm writing todo-list app. The last missing piece is option to editting selected item (onClick). I have problem with doing that.
Could you tell me how i can achieve that?
I looking for solution like that:
I don't know how to make editing mode so my input form can handle updating existing item.
// ACTION
export const editTask = (task) => ({
type: "EDIT_TASK",
payload: task,
});
// REDUCER
const INITIAL_STATE = {
tasks: [],
alert: {
show: false,
message: "",
type: "",
},
isEditing: false,
};
const reducer = (state, action) => {
switch (action.type) {
case "EDIT_TASK":
return {
...state,
isEditing: true,
// take current tasks and updatedTask
tasks: [...state.tasks, action.payload],
alert: setAlert(true, "Task has changed succesfull 🌈", "success"),
};
default:
return state;
On my todo.jsx
const TasksTodo = () => {
const [inputValue, setInputValue] = useState("");
const [state, dispatch] = useReducer(reducer, INITIAL_STATE);
const editTaskFromList = (item) => {
// match tasks from list with that selected
const taskToEdit = state.tasks.find(
(taskToFind) => taskToFind.id === item.id
);
const editedTask = {
taskToEdit,
title: inputValue,
};
dispatch(editTask([...state.tasks, editedTask]));
};
const handleSubmit = (e) => {
e.preventDefault();
if (inputValue) {
const newItem = {
id: new Date().getTime().toString(),
title: inputValue,
};
dispatch(addNewTask(newItem));
setInputValue("");
} else {
dispatch({ type: "NO_VALUE" });
}
};
const handleChange = (e) => {
setInputValue(e.target.value);
};
return (
<div className="tasks-list-section">
<h3 className="tasks__title">tasks List </h3>
{state.alert.show && (
<Alert
{...state.alert}
removeAlert={() => dispatch(changeAlertState())}
/>
)}
<form onSubmit={handleSubmit} className="tasks__form">
<input
type="text"
value={inputValue}
placeholder="e.g homework"
className="tasks__input"
onChange={handleChange}
/>
<button type="submit" className="tasks__submit-btn">
{state.isEditing ? "edit" : "submit"}
</button>
</form>
{state.tasks.length > 0 && (
<div className="tasks__container">
<Tasks
listItems={state.tasks}
removeTask={removeTaskFromList}
editTask={editTaskFromList}
/>
</div>
)}
</div>
);
};
TaskList Component:
const Tasks = ({ listItems, editTask, removeTask }) => {
return (
<div className="tasks-list">
{listItems.map((item) => {
const { id, title } = item;
return (
<div key={id} className="tasks__item">
<p className="tasks__item--title">{title}</p>
<div className="tasks__button-group">
<button
type="button"
className="tasks__button-group--edit"
onClick={() => editTask(item)}
>
<RiEditBoxLine className="size" />
</button>
<button
type="button"
className="tasks__button-group--delete"
onClick={() => removeTask(item)}
>
<RiDeleteBin6Line className="size" />
</button>
</div>
</div>
);
})}
</div>
);
};
Upvotes: 0
Views: 1643
Reputation:
I found different solution. Rate my code if you can.
On my reducer
case "EDIT_TASK":
return {
...state,
isEditing: true,
tasks: [
...state.tasks.filter((task) => task.id !== action.payload.id),
action.payload,
],
alert: setAlert(true, "Task has changed succesfull 🌈", "success"),
};
tasks.jsx
const editTaskFromList = (item) => {
const taskToEdit = state.tasks.find(
(taskToFind) => taskToFind.id === item.id
);
setEditingTaskID(taskToEdit.id);
setInputValue(taskToEdit.title);
};
const handleSubmit = (e) => {
e.preventDefault();
if (editingTaskID === null) {
if (inputValue) {
const newItem = {
id: new Date().getTime().toString(),
title: inputValue,
};
dispatch(addNewTask(newItem));
setInputValue("");
} else {
alert("Value cannot be empty!");
}
} else {
const editingItem = state.tasks.find((task) => task.id === editingTaskID);
const newItem = { ...editingItem, title: inputValue };
dispatch(editTask(newItem));
setInputValue("");
setEditingTaskID(null);
}
};
Upvotes: 0
Reputation: 1108
Please find the simple workaround for this.
Page.js ( Main Component)
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { addTask, editTask, removeTask } from "./actions";
const TaskList = ({ tasks, removeTask, editTask }) => {
return (
<div>
{tasks.map((item) => (
<div key={item.id}>
<p>{item.title}</p>
<button type="button" onClick={(e) => editTask(item)}>
Edit
</button>
<button type="button" onClick={(e) => removeTask(item)}>
Remove
</button>
</div>
))}
</div>
);
};
function Page() {
const tasks = useSelector((state) => state.tasks);
const dispatch = useDispatch();
const [inputValue, setInputValue] = useState("");
const [editingTaskIndex, setEditingTaskIndex] = useState(null);
const editTaskFromList = (task) => {
const taskToEdit = tasks.find((item) => item.id === task.id);
const taskIndex = tasks.indexOf(taskToEdit);
setEditingTaskIndex(taskIndex);
setInputValue(taskToEdit.title);
};
const removeTaskFromList = (task) => {
const taskToDelete = tasks.find((item) => item.id === task.id);
const taskIndex = tasks.indexOf(taskToDelete);
dispatch(removeTask(taskIndex));
};
const handleSubmit = (e) => {
e.preventDefault();
if (editingTaskIndex === null) {
const newItem = {
id: new Date().getTime().toString(),
title: inputValue
};
dispatch(addTask(newItem));
} else {
const editingItem = tasks[editingTaskIndex];
editingItem.title = inputValue;
dispatch(editTask(editingTaskIndex, editingItem));
}
setInputValue("");
setEditingTaskIndex(null);
};
const handleChange = (e) => {
setInputValue(e.target.value);
};
return (
<div>
<h3>Task List</h3>
<form onSubmit={handleSubmit}>
<input
type="text"
value={inputValue}
placeholder="e.g: homework"
onChange={handleChange}
/>
<button>Submit</button>
</form>
<TaskList
tasks={tasks}
editTask={editTaskFromList}
removeTask={removeTaskFromList}
/>
</div>
);
}
export default Page;
reducer.js
const initialState = {
tasks: [],
isEditing: false
};
function taskReducer(state = initialState, action) {
switch (action.type) {
case "ADD_TASK":
return { ...state, tasks: [...state.tasks, action.payload] };
case "EDIT_TASK":
console.log(action.payload);
const currentTasks = Array.from(state.tasks);
currentTasks[action.payload.taskIndex] = action.payload.task;
return { ...state, tasks: currentTasks };
case "REMOVE_TASK":
const allTasks = Array.from(state.tasks);
allTasks.splice(action.payload, 1);
return {
...state,
tasks: allTasks
};
default:
return state;
}
}
export default taskReducer;
Upvotes: 3