将功能组件传递给 React Spring 的 useTransition
Passing Functional Components to React Spring's useTransition
我正在尝试编写一个包含按钮面板的 React 组件,每个按钮都需要能够根据应用程序的状态独立地打开和关闭。为此,我创建了一个 useTransition
,包裹在一个自定义挂钩中,它应该在收到新的 SVG 功能组件时触发转换。
我遇到的问题是,虽然按钮当前正在正确过渡,但我似乎无法让 useTransition
在接收到新组件时将它们换出。当组件被一个空数组替换时,它会删除一个,这是预期的,并且当传入一个新组件时,挂钩内的 useEffect
触发,但由于某种原因,更改没有被 useTransition
。
我猜它与组件之间的对象相等性有关,但我不知道如何在不强制更改 window.requestAnimationFrame
以设置状态两次的情况下解决它。这是一个带有最小演示的 codesandbox。
父组件:
import React, { useState } from "react";
import { a } from "react-spring";
import "./styles.css";
import PlaySVG from "./svgs/PlaySVG";
import SaveSVG from "./svgs/SaveSVG";
import SearchSVG from "./svgs/SearchSVG";
import TrashSVG from "./svgs/TrashSVG";
import { useVertTransition } from "./Hooks";
export default function ActionButtons() {
const svgs = {
play: <PlaySVG style={{ width: "100%", height: "auto" }} id="play" />,
search: <SearchSVG style={{ width: "80%", height: "auto" }} id="search" />,
save: <SaveSVG style={{ width: "80%", height: "auto" }} id="save" />,
trash: <TrashSVG style={{ width: "80%", height: "auto" }} id="trash" />
};
const [actions, setActions] = useState({
one: svgs.play,
two: svgs.search,
three: svgs.trash
});
const [slotOne] = useVertTransition(actions.one);
const [slotTwo] = useVertTransition(actions.two);
const [slotThree] = useVertTransition(actions.three);
function buttonHandler() {
setActions({
...actions,
one: [],
two: svgs.save
});
}
return (
<div className="container">
<div className="panel">
<div className="button-container">
{slotOne.map(({ item, props, key }) => (
<a.button key={key} style={props} onClick={buttonHandler}>
{item}
</a.button>
))}
</div>
<div className="button-container">
{slotTwo.map(({ item, props, key }) => (
<a.button key={key} style={props} onClick={buttonHandler}>
{item}
</a.button>
))}
</div>
<div className="button-container">
{slotThree.map(({ item, props, key }) => (
<a.button key={key} style={props} onClick={buttonHandler}>
{item}
</a.button>
))}
</div>
</div>
</div>
);
}
useVertTransition 钩子:
import React, { useEffect } from "react";
import { useTransition } from "react-spring";
export function useVertTransition(item) {
useEffect(() => {
console.log(item);
}, [item]);
const vertTransition = useTransition(item, null, {
from: { transform: "translateY(-20px) rotateX(-90deg)", opacity: 0 },
enter: { transform: "translateY(0px) rotateX(0deg)", opacity: 1 },
leave: { transform: "translateY(20px) rotateX(90deg)", opacity: 0 },
trail: 400,
order: ["leave", "enter"]
});
return [vertTransition];
}
SVG 组件示例:
import React from "react";
function PlaySVG({ style }) {
return (
<svg xmlns="http://www.w3.org/2000/svg" style={style} viewBox="0 0 24 24">
<path d="M7 6L7 18 17 12z" />
</svg>
);
}
export default PlaySVG;
你是对的,react-spring 无法检测按钮之间的差异。但它不检查项目,它只检查键。所以你必须为唯一键添加一些东西。因此,您可能希望将输入从 svg 更改为在 svg 旁边包含名称的对象。
const getSvg = name => ({ name, svg: svgs[name] });
const [actions, setActions] = useState({
one: getSvg("play"),
two: getSvg("search"),
three: getSvg("trash")
});
您现在可以添加按键功能:
const vertTransition = useTransition(item, svg => svg.name, {
你应该更改渲染:
{slotOne.map(({ item, props, key }) => (
<a.button key={key} style={props} onClick={buttonHandler}>
{item.svg}
</a.button>
))}
现在它按预期工作了。我觉得。
https://codesandbox.io/s/usetransition-demo-152zb?file=/src/ActionButtons.js:1253-1437
而且我还学会了一个新技巧,我从来没用过命令属性。
我正在尝试编写一个包含按钮面板的 React 组件,每个按钮都需要能够根据应用程序的状态独立地打开和关闭。为此,我创建了一个 useTransition
,包裹在一个自定义挂钩中,它应该在收到新的 SVG 功能组件时触发转换。
我遇到的问题是,虽然按钮当前正在正确过渡,但我似乎无法让 useTransition
在接收到新组件时将它们换出。当组件被一个空数组替换时,它会删除一个,这是预期的,并且当传入一个新组件时,挂钩内的 useEffect
触发,但由于某种原因,更改没有被 useTransition
。
我猜它与组件之间的对象相等性有关,但我不知道如何在不强制更改 window.requestAnimationFrame
以设置状态两次的情况下解决它。这是一个带有最小演示的 codesandbox。
父组件:
import React, { useState } from "react";
import { a } from "react-spring";
import "./styles.css";
import PlaySVG from "./svgs/PlaySVG";
import SaveSVG from "./svgs/SaveSVG";
import SearchSVG from "./svgs/SearchSVG";
import TrashSVG from "./svgs/TrashSVG";
import { useVertTransition } from "./Hooks";
export default function ActionButtons() {
const svgs = {
play: <PlaySVG style={{ width: "100%", height: "auto" }} id="play" />,
search: <SearchSVG style={{ width: "80%", height: "auto" }} id="search" />,
save: <SaveSVG style={{ width: "80%", height: "auto" }} id="save" />,
trash: <TrashSVG style={{ width: "80%", height: "auto" }} id="trash" />
};
const [actions, setActions] = useState({
one: svgs.play,
two: svgs.search,
three: svgs.trash
});
const [slotOne] = useVertTransition(actions.one);
const [slotTwo] = useVertTransition(actions.two);
const [slotThree] = useVertTransition(actions.three);
function buttonHandler() {
setActions({
...actions,
one: [],
two: svgs.save
});
}
return (
<div className="container">
<div className="panel">
<div className="button-container">
{slotOne.map(({ item, props, key }) => (
<a.button key={key} style={props} onClick={buttonHandler}>
{item}
</a.button>
))}
</div>
<div className="button-container">
{slotTwo.map(({ item, props, key }) => (
<a.button key={key} style={props} onClick={buttonHandler}>
{item}
</a.button>
))}
</div>
<div className="button-container">
{slotThree.map(({ item, props, key }) => (
<a.button key={key} style={props} onClick={buttonHandler}>
{item}
</a.button>
))}
</div>
</div>
</div>
);
}
useVertTransition 钩子:
import React, { useEffect } from "react";
import { useTransition } from "react-spring";
export function useVertTransition(item) {
useEffect(() => {
console.log(item);
}, [item]);
const vertTransition = useTransition(item, null, {
from: { transform: "translateY(-20px) rotateX(-90deg)", opacity: 0 },
enter: { transform: "translateY(0px) rotateX(0deg)", opacity: 1 },
leave: { transform: "translateY(20px) rotateX(90deg)", opacity: 0 },
trail: 400,
order: ["leave", "enter"]
});
return [vertTransition];
}
SVG 组件示例:
import React from "react";
function PlaySVG({ style }) {
return (
<svg xmlns="http://www.w3.org/2000/svg" style={style} viewBox="0 0 24 24">
<path d="M7 6L7 18 17 12z" />
</svg>
);
}
export default PlaySVG;
你是对的,react-spring 无法检测按钮之间的差异。但它不检查项目,它只检查键。所以你必须为唯一键添加一些东西。因此,您可能希望将输入从 svg 更改为在 svg 旁边包含名称的对象。
const getSvg = name => ({ name, svg: svgs[name] });
const [actions, setActions] = useState({
one: getSvg("play"),
two: getSvg("search"),
three: getSvg("trash")
});
您现在可以添加按键功能:
const vertTransition = useTransition(item, svg => svg.name, {
你应该更改渲染:
{slotOne.map(({ item, props, key }) => (
<a.button key={key} style={props} onClick={buttonHandler}>
{item.svg}
</a.button>
))}
现在它按预期工作了。我觉得。
https://codesandbox.io/s/usetransition-demo-152zb?file=/src/ActionButtons.js:1253-1437
而且我还学会了一个新技巧,我从来没用过命令属性。