user14507093
user14507093

Reputation:

What is the best way to update item in React Redux

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:

  1. Select item which you want to update (by clicking on edit icon)
  2. Form should change into "editing mode" so user can pass new value into editing item.
  3. When value is passed, then user click on submit button.

enter image description here

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

Answers (2)

user14507093
user14507093

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

Dulaj Ariyaratne
Dulaj Ariyaratne

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;

Checkout the sandbox link

Upvotes: 3

Related Questions