Framer Motion reorder failing silently with nested items

Viewed 591

I have an array of questions that I'm trying to animate using Framer Motion. The shape roughly looks like:

const questionList = [
  {
    type: "text",
    data: {
      question: "What is your name?",
      valid: true,
    },
  },
  {
    type: "text",
    data: {
      question: "How old are you?",
      valid: true,
    },
  },
  {
    type: "multi",
    data: {
      question: "What are your favorite sports?",
      responses: ["Football", "Hockey", "Tennis", "Chess"],
      valid: true,
    },
  },
  {
    type: "single",
    data: {
      question: "What is your gender?",
      responses: ["Male", "Female", "Don't know"],
      valid: true,
    },
  },
];

I am rendering them in a list of cards using React and Tailwind like so:

export default function QuestionList() {

  const [questions, setQuestions] = React.useState(questionList);

  return (
    <Reorder.Group values={questions} onReorder={setQuestions}>
      {questions.map((question, index) => {
        return (
          <Reorder.Item
            className="mb-4 px-4 py-6 bg-indigo-500 text-white ml-12 border-2 border-gray-100 shadow rounded-md cursor-move hover:shadow-md"
            key={`question${question.type}${index}`}
            value={`question${question.type}${index}`}>
            {question.data.question}
          </Reorder.Item>
        );
      })}
    </Reorder.Group>
  );
}

I'd like to be able to reorder the cards using Framer Motion Reorder components as described here https://www.framer.com/docs/reorder/ but every time I try the component tree crashes silently and I get a blank screen. When I reduce the questions to a flat structure like ['Question 1', 'Question 2'] etc I am able to get the re-ordering to happen. I suspected it could be something to do with the keys but playing around with that doesn't work. Grateful for any help/pointers

2 Answers

Besides the key having to be unique, you also should set value from Reorder.Item to value={question}. If you want to generate a unique ID for each question, perhaps consider using a library such as uuidv4

You shouldn't use the loop index as the key in your Reorder.Item. When you drag to reorder the item, the index (and thus the key) will change. That will make it impossible for Reorder to track which elements have been moved to where and is probably why it's crashing.

Instead use a value like a unique id property for each question. This way React (and Framer Motion) will know exactly which element was moved and can render it at the new position.

Here's a more thorough explanation:
react key props and why you shouldn’t be using index

Related