将功能组件传递给 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

而且我还学会了一个新技巧,我从来没用过命令属性。