使用键时复制组件
Component duplicating when using keys
我正在尝试使用 Framer Motion 在 React 中制作组件轮播。 AnimatePresence
的 children 需要一个键,所以我决定传递一个页面状态作为键。但是,这样做会使我尝试渲染的组件重复。我认为这是因为密钥最终会是 re-used,所以我创建了一个函数来生成一个随机字符串用作密钥,但它也复制了组件。
使用轮播的组件
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 上
当我不使用按键时,它会按预期工作,但是每当我单击其中一个箭头按钮时,它都会抛出以下警告
P.S 我知道最终页面值会超出 projects
的长度范围,我计划在解决此问题后修复它。
其实这里不需要任何密钥。
为反应管理的元素添加键(以及添加随机键 - 正如您使用 Math.random()
方法所做的那样)将覆盖反应预定义的键,并可能导致您的程序在您到达此处时出现某种渲染错误。
仅当您从数组生成组件时才需要键(例如使用 map 函数)。
来自doc :
Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity:
这里不需要。
此外,每次渲染的密钥都必须相同,这里您生成一个随机密钥(每次渲染此组件时都使用数学随机方法)。
既然你正在使用这个库: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;
我正在尝试使用 Framer Motion 在 React 中制作组件轮播。 AnimatePresence
的 children 需要一个键,所以我决定传递一个页面状态作为键。但是,这样做会使我尝试渲染的组件重复。我认为这是因为密钥最终会是 re-used,所以我创建了一个函数来生成一个随机字符串用作密钥,但它也复制了组件。
使用轮播的组件
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 上
当我不使用按键时,它会按预期工作,但是每当我单击其中一个箭头按钮时,它都会抛出以下警告
P.S 我知道最终页面值会超出 projects
的长度范围,我计划在解决此问题后修复它。
其实这里不需要任何密钥。
为反应管理的元素添加键(以及添加随机键 - 正如您使用 Math.random()
方法所做的那样)将覆盖反应预定义的键,并可能导致您的程序在您到达此处时出现某种渲染错误。
仅当您从数组生成组件时才需要键(例如使用 map 函数)。
来自doc :
Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity:
这里不需要。
此外,每次渲染的密钥都必须相同,这里您生成一个随机密钥(每次渲染此组件时都使用数学随机方法)。
既然你正在使用这个库: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;