How to save/reload the state of `ion-reorder-group`?

The docs for IonReorderGroup give this code:

import React, { useState } from 'react';
import { IonItem, IonLabel, IonList, IonReorder, IonReorderGroup, ItemReorderEventDetail } from '@ionic/react';

function Example() {
  const [items, setItems] = useState([1, 2, 3, 4, 5]);

  function handleReorder(event: CustomEvent<ItemReorderEventDetail>) {
    // Before complete is called with the items they will remain in the
    // order before the drag
    console.log('Before complete', items);

    // Finish the reorder and position the item in the DOM based on
    // where the gesture ended. Update the items variable to the
    // new order of items
    setItems(event.detail.complete(items));

    // After complete is called the items will be in the new order
    console.log('After complete', items);
  }

  return (
    <IonList>
      {/* The reorder gesture is disabled by default, enable it to drag and drop items */}
      <IonReorderGroup disabled={false} onIonItemReorder={handleReorder}>
        {items.map((item) => (
          <IonItem key={item}>
            <IonLabel>Item {item}</IonLabel>
            <IonReorder slot="end"></IonReorder>
          </IonItem>
        ))}
      </IonReorderGroup>
    </IonList>
  );
}
export default Example;

In my app, I want to let users rearrange items in a certain order, and I want to save the state to my server.

I’m using react-hook-form and I can do that pretty easily.

But, how do I set the initial state of IonReorderGroup? For example, say the user previously updated the state of items to [5,4,3,2,1]; how do I get IonReorderGroup to show the items in that order when the component is loaded?

The problem is that you can’t just change the line const [items, setItems] = useState[5,4,3,2,1] like you would normally set state in React. It seems to be that you need to do something like a one-time useEffect() on component load and then manually trigger handleReorder(), but I’m having trouble getting that to work.

It looks like according to this issue, there’s no way to provide the state to IonReorder. So I guess the solution is “write a custom function to keep track of all my reorder items as UUIDs, and map that to the IonReorder array indices, and then save the UUID order to the server.” :confused:

Hmmm…I have a display_order prop on the objects that are being displayed. So on initial render, they are ordered based on that.

When the reorder is complete, I loop through the objects and set display_order to their new order.

1 Like

@twestrick Thanks for your response. What you suggest is similar to the approach I ended up taking.

What I did was change how the data was stored in my backend. Instead of storing the Ionic values (1,2,3,4, etc.), I used strings as keys to represent the actual items being stored. That way, I can just reorder my own array based on the from and to properties of the reorder event.

Here’s a simplified version of the code I used:

// https://stackoverflow.com/a/66345540
const reorderArray = (from: number, to: number, arr: string[]) => {
  const newArr = [...arr];

  const item = newArr.splice(from, 1)[0];
  newArr.splice(to, 0, item);

  return newArr;
};

const FormReorder: React.FC<UserFormReorderControl> = ({
  control,
  drupalOrder,
  setValue,
}: UserFormReorderControl) => {
  const handleReorder = useCallback(
    (event: CustomEvent<ItemReorderEventDetail>) => {
      // The `from` and `to` properties contain the index of the item
      // when the drag started and ended, respectively
      const reorderedSet = reorderArray(
        event.detail.from,
        event.detail.to,
        drupalOrder,
      );

      // Finish the reorder and position the item in the DOM based on
      // where the gesture ended. Update the items variable to the
      // new order of items
      event.detail.complete();
      setValue('rephraseOrder', reorderedSet);
    },
    [drupalOrder, setValue],
  );

  return (
    <IonList>
      {/* The reorder gesture is disabled by default, enable it to drag and drop items */}
      <IonReorderGroup disabled={false} onIonItemReorder={handleReorder}>
        {drupalOrder.map((item) => (
          <FormReorderItem
            control={control}
            key={item}
            item={item}
          />
        ))}
      </IonReorderGroup>
    </IonList>
  );
};

export default FormItemReorder;
1 Like