[go: up one dir, main page]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent state management or perhaps funky animation (maybe im dumb?¿) #63

Open
Stianlars1 opened this issue May 15, 2024 · 1 comment

Comments

@Stianlars1
Copy link
Stianlars1 commented May 15, 2024

im using nextjs (react).

Let's jump right into it:

My component looks something like this:

interface Props {
tasks: {
"CREATED": [
{id: 1, title: "xyz"},
{id: 2, title: "123"}
],
"COMPLETED": [
{id: 3, title: "ABC"},
{id: 4, title: "456"}
]
}
}
export const MyComponent = ({tasks}: Props) => {
const tasksList: ColumnListDND[] = Object.entries(tasks).map(
    ([statusString, todosList]) => ({
      column: statusString,
      tasks: todosList,
    })
  );
}

  const [parent, columns, setColumnsList, updateConfig] = useDragAndDrop<
    HTMLUListElement,
    ColumnListDND
  >(
    tasksList,

    {
      dragHandle: ".column-drag-handle",
      group: COLUMN_GROUP,
      plugins: [animations()],
      name: "ColumnsListWrapper",

      draggable: (el) => {
        return el.attributes.getNamedItem("data-group")?.value == COLUMN_GROUP;
      },

      handleEnd: async (data) => {
        if (data.e.target instanceof HTMLElement) {
          if (data.e.target.getAttribute("data-group") == TASKCARD_GROUP) {
            // Needs this cause the drag of a task also fires of this.
            return;
          }
        }

        const didIndexChange = didCategoryIndexChange({
          oldList: tasksList,
          newList: columns,
        });

        // If order didnt change, no need to do update
        if (!didIndexChange) {
          return;
        }

        // save the new displayOrder of the columns
        const columnsUpdateResponse = await handleUpdateColumnsOrder(columns);

        if (columnsUpdateResponse.isError) {
          toast.error(
            "An error occured while updating the sort preference of the status columns"
          );
        }
        console.log("🟢 columnsUpdateResponse", columnsUpdateResponse);
        await cacheInvalidate({ cacheKey: CacheKeys.USER_PREFERENCES });
        await cacheInvalidate({ cacheKey: CacheKeys.CATEGORIZED_TODOS });

        toast.success("Column was updated successfully", "bottomRight");
      },

      sortable: true,
    }
  );
  
  
  useEffect(() => {
    if (tasks && tasksList

https://github.com/formkit/drag-and-drop/assets/71408982/cc9e84a8-2a47-40fb-9fd4-5fb61cc17c21

) {
      setColumnsList(tasksList);
    }
  }, [tasks]);
  
  
  return (
  <>
          {columns.map((columnObject: ColumnListDND, index: number) => (
          <DraggableColumn
            data-label={columnObject.column}
            key={columnObject.column}
            columnObject={columnObject}
          />
        ))}
      </ul>
        </>
  )
  }

My problem?
Lets think about this scenario:

  1. I grab and drag a column and drop it inbetween some other columns
  2. I then save this preference in my backend
  3. on update success, i cache invalidate the fetch call for the tasks my component receives

when i cache invalidate the fetch call that gives my component the "tasks", my useEffect will fire and update the columns by the setActionState the useDragAndDrop returns for us. This leads to a weird animation where my original first page load setup will re-animate to the new positions, but in a funky way. Please view the attached video for more context about the problem.

the problem is that the tasksList i receive after cache invalidation is exactly the same as the current "column" list reutrned by the useDragAndDrop hook, so they shouldnt actually have any animations since theres nothing to animate. but i guess maybe theres some initial state you guys do when setting up the hook?

has this problem been mentioned before? are you guys aware of this?

please see the video attached

Be aware: the example code above is just an illustration cause i dont want the actual code displayed here, but thats pretty much how it works.

also: why do i need useEffect to update the state? why cant the useDragAndDrop hook just do the changes when the tasksList gets updated? you see, if i console log out the tasksList and columns variables before and after the cache invalidation take place, the columns variable returned by the hook wont reflect the input argument of tasksList the hook receives. But i figure theres some kind of state you guys do that affect how i want it to work.

funkyAnimation.mov
@Stianlars1
Copy link
Author

I can follow up with a solution i got

By resetting the state by the resetState function provided by formkit library and updating the state with the setstateAction with the new value worked.

// Import
import {  animations,  resetState } from "@formkit/drag-and-drop";

// usage
const tasksList: ColumnListDND[] = Object.entries(tasks).map(
    ([statusString, todosList]) => ({
      column: statusString,
      tasks: todosList,
    })
  );
}

  const [parent, columns, setColumnsList, updateConfig] = useDragAndDrop<HTMLUListElement, ColumnListDND>(tasksList, {...})

  useEffect(() => {
    if (tasksList) {
      resetState();
      setColumnsList(tasksList);
    }
  }, [tasks]);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant