2

I have developed a simple todo app using react-beautiful-dnd. I am able to retrieve data from the database and display it in the list. However, when I try to drag and rearrange the order, the reordered array is getting printed in the console (I tried testing using console.log), however the new reorderd array is not getting displayed in the interface. I am very new to this MERN stack, therefore I am unable to find the reason for this error.

I have attached screenshots of the output before and after dragging an element, and also the console log output.

before drag-and-drop

after drag and drop

console-log array order before drag and drop

console-log reordered array

The code :

function ProjectsDashboard() {

  useEffect(() => {
    preload();
  }, []);

  const [state, setState] = useState([]);
  const[stage,setStage] = useState([]);
  const [todo, setTodo] = useState("");
  const [loading, setLoading] = useState(false);

  const preload = async () => {
    setLoading(true);
    try {
      const res = await axios.get("/stages");
      setState(res.data);
      console.log(state, "STATE")
      console.log(res.data,"DATA")
      setLoading(false);
    } catch (error) {
      alert("Couldn't find any Todos! ");
      setLoading(false);
    }
  };

  var formattedArray =state.stage && state.stage.map(item => Object.keys(item).map(i => item[i]));
  console.log(formattedArray, "FORMATTED ARRAY")
  // setState( formattedArray);
  // console.log(state, "STATE")

  
  const lists = () => (
    <div className="row">
      <div className="col-sm-12 col-md-4 offset-md-2 col-lg-4 offset-lg-2 border border-danger p-4">
        <h3 className="text-center mb-4">Draggable List</h3>
        <DragDropContext onDragEnd={handleDragEnd}>
          <Droppable droppableId="todos">
            {(provided) => (
              <ul
                className="list-group"
                {...provided.droppableProps}
                ref={provided.innerRef}
              >
                 {console.log("HELLO-out")}
              {state.stage && state.stage.map((item, index) => (
               
                  <Draggable
                    key={item._id}
                    draggableId={item._id + ""}
                    index={index}
                  >
                    {(provided) => (
                      <li
                        className="list-group-item d-flex justify-content-between align-items-start align-items-center"
                        {...provided.draggableProps}
                        {...provided.dragHandleProps}
                        ref={provided.innerRef}
                      >
                            {console.log("HELLO")}
                        <div className="ms-2 me-auto">
                    

                          <span className="font-weight-bold">{item.stageName}</span>
                        </div>

                        <span>
                          {/* <i className="bi bi-trash text-danger" /> */}
                          <button
                            className="btn btn-sm"
                            onClick={(e) => {
                              e.preventDefault();
                              handleDelete(item._id, index);
                            }}
                          >
                            <i className="bi bi-trash text-danger" />
                          </button>
                        </span>
                      </li>
                    )}
                  </Draggable>
                ))}
                {provided.placeholder}
              </ul>
            )}
          </Droppable>
        </DragDropContext>
      </div>
      <div
        className="col-sm-12 col-md-4 col-lg-4 border border-info p-4"
        style={{ marginLeft: "10px" }}
      >
        <h3 className="text-center mb-4">NON-Draggable List</h3>

        <ul className="list-group">
          {state.stage && state.stage.map(
            (item, index) =>
              item.selected && (
                <li className="list-group-item" key={index}>
                  {item.title}
                </li>
              )
          )}
        </ul>
      </div>
    </div>
  );


  const handleDragEnd = (result) => {
    console.log(result.destination,"DESTI");
    if (!result.destination) return;
    const items = Array.from(state.stage);
    console.log(items,"ITEMS-DRAG")
    console.log(result.source.index,"SOURCE INDEX")
    console.log(result.destination.index,"DESTINATION INDEX")
    const [recordedItem] = items.splice(result.source.index, 1);
    console.log(recordedItem,"RECORDED")
     items.splice(result.destination.index, 0, recordedItem);
    console.log(items, "NEW ITEM")
    setState(items);
     console.log(state, "STATE");
  };

  const handleDelete = async (id, index) => {
    try {
      await axios.delete(`/api/todo/${id}`);
      // preload();
      const temp = Array.from(state);
      temp.splice(index, 1);
      setState(temp);
    } catch (error) {
      if (`Error! ${error.response.data.err}`) {
        alert(error.response.data.err);
      } else {
        alert(`Error ${error.response.status}: ${error.response.statusText}`);
      }
    }
  };

  const addNewTodoForm = () => (
    <div className="row">
      <div className="col-md-8 offset-md-2 mb-4 form-group">
        <label htmlFor="newtodo">Add a New Todo Item</label>
        <input
          type="text"
          className="form-control"
          name="newtodo"
          id="newtodo"
          value={todo}
          placeholder="Add New Todo"
          required
          onChange={handleChange}
        />

        <button
          className="btn btn-block btn-outline-primary mt-2"
          onClick={handleSubmit}
        >
          Submit
        </button>
      </div>
    </div>
  );

  const handleChange = (e) => {
    e.preventDefault();
    setTodo(e.target.value);
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (todo === "" || todo === null) {
      alert(
        "To add a New Todo item, please fill out the 'Add New Todo' field."
      );
      return;
    }
    const temp = {
      title: todo,
    };
    try {
      const res = await axios.post("/api/todo", temp);
      setTodo("");
      const tmp = Array.from(state);
      tmp.push(res.data);
      setState(tmp);
      // preload();
    } catch (error) {
      if (error.response.data && error.response.data.err) {
        alert(`Error! ${error.response.data.err}`);
      } else {
        console.log(error);
        alert(`Error ${error.response.status}: ${error.response.statusText}`);
      }
    }
  };
  return (
    <>
      <div className="container">
        <h1 className="text-center m-4 font-weight-bold text-uppercase">
          DRAG TO DO{" "}
          <span className="text-lowercase font-weight-normal">V1.0.1</span>
        </h1>
        {/* {addNewTodoForm()}*/}
        { lists() }
      </div>
    </>
  );
};

export default ProjectsDashboard;
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 1
    Your state situation is a little odd. You've got `state`, `stage`, `todo`, and `loading` using `useState`. `state` has a default value of `[]`, and yet one of the first things done with it is to get a `stage` property from it (`var formattedArray =state.stage...`). While it's certainly possible to have properties on arrays (they're objects like any others), it's an unusual design practice to be sure. You also never use `stage` or `setStage`, so it's unclear what those are for. I would suggest using just `state` and not `state.stage`. – Heretic Monkey Aug 25 '21 at 20:19

0 Answers0