Дублирование компонентов при использовании ключей - PullRequest
0 голосов
/ 01 августа 2020

Я пытаюсь создать карусель компонентов в React, используя Framer Motion. Потомкам AnimatePresence нужен ключ, поэтому я решил передать состояние страницы в качестве ключа. Однако при этом компонент, который я пытаюсь визуализировать, дублируется. Я думал, что это потому, что ключ в конечном итоге будет повторно использован, поэтому я создал функцию, которая генерирует случайную строку для использования в качестве ключа, но также дублирует компонент.

Компонент с использованием карусели

const ProjectList = props => {

  const [page, setPage] = useState(0);

  const projects = [
    <Project 
      name="Example"
      desc="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Libero nunc consequat interdum varius sit amet."
      image={require("../img/exampleproject.png")}
    />,
    <Project 
      name="Example2"
      desc="Another example. This one does nothing too. What a suprise!"
      image={require("../img/exampleproject.png")}
    />
  ]

  const genKey = () => {
    return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
  }

  const paginate = (newPage) => {
    setPage(newPage)
  }

  return (
    
    <div className="project-list">
      <AnimatePresence>
        <motion.button key={genKey()} onClick={() => paginate(page-1)}>
          <ArrowBackIosIcon/>
        </motion.button>
        <motion.div key={genKey()} className="project-list"
          initial={{opacity: 0}}
          animate={{opacity: 1}}
          exit={{opacity: 0}}
        >
          {projects[page]}
        </motion.div>
        <motion.button key={genKey()} onClick={() => paginate(page+1)}>
          <ArrowForwardIosIcon/>
        </motion.button>
      </AnimatePresence>
    </div>
  );

Я не уверен, как использовать библиотеки, такие как Framer Motion, в редакторе сниппетов, поэтому я поместил его в CodeSandbox

Edit priceless-sammet-9w1t3

When I don't use a key, it works as expected, however whenever I click one of the arrow buttons it throws the following warnings

предупреждения

PS Я знаю, что в конечном итоге значение страницы будет go вне диапазона длины projects, я планирую исправить это, как только смогу решить эту проблему.

1 Ответ

2 голосов
/ 01 августа 2020

На самом деле вам здесь не нужен ключ. Добавление ключа (и, более того, добавление случайных ключей - как вы это делали с методом Math.random()) для элементов, которые реагируют на управление, переопределит предварительно определенные ключи реакции и может привести вашу программу к ошибкам рендеринга, как вы здесь.

Ключи необходимы только тогда, когда вы генерируете компоненты из массива (например, с функцией карты).

Из do c:

Ключи помогают React определить, какие элементы были изменены, добавлены или удалены. Ключи должны быть присвоены элементам внутри массива, чтобы придать элементам стабильную идентичность :

Здесь вам это не нужно.

Также ключ должен будет одинаковым для каждого рендеринга, и здесь вы генерируете случайный ключ (из математического метода random каждый раз, когда вы визуализируете этот компонент).

Теперь, поскольку вы используете эту библиотеку: https://www.framer.com/api/motion/animate-presence/#usage

Уточнено, что вам нужно использовать ключ. Проблема здесь в том, что вы должны давать постоянные ключи. Так что удалите функцию Math Random и дайте некоторую постоянную строку, как я здесь:

import React, { useState } from "react";
import Section from "./Section.js";
import { AnimatePresence, motion } from "framer-motion";
import Project from "./Project.js";
import ArrowBackIosIcon from "@material-ui/icons/ArrowBackIos";
import ArrowForwardIosIcon from "@material-ui/icons/ArrowForwardIos";

const ProjectList = props => {
  const [page, setPage] = useState(0);

  const projects = [
    <Project
      name="Example"
      desc="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Libero nunc consequat interdum varius sit amet."
      image={
        "https://i.picsum.photos/id/928/600/300.jpg?hmac=ai-33AKRXhJnTcm88ArxRypuNNrfztMdJ-ui_8dhe8c"
      }
    />,
    <Project
      name="Example2"
      desc="Another example. This one does nothing too. What a suprise!"
      image={
        "https://i.picsum.photos/id/258/600/300.jpg?hmac=d-pTq52drP8dj3vsxB72sOgifDUNcookREV33ffONbw"
      }
    />
  ];



  const paginate = newPage => {
    setPage(newPage);
  };

  return (
    <div className="project-list">
      <AnimatePresence>
        <motion.button key="img1" onClick={() => paginate(page - 1)}>
          <ArrowBackIosIcon />
        </motion.button>
        <motion.div
          key="img2"
          className="project-list"
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
        >
          {projects[page]}
        </motion.div>
        <motion.button key="img3" onClick={() => paginate(page + 1)}>
          <ArrowForwardIosIcon />
        </motion.button>
      </AnimatePresence>
    </div>
  );
};

export default ProjectList;


Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...