我正在开发一个简单的Reaction应用程序,它涉及到在棋盘上移动瓷砖.该应用程序使用css来制作动画,并使用Reaction状态来跟踪瓷砖的位置.我有一个转换函数,可以更新瓷砖的位置,希望每个瓷砖都能动画显示到它的新位置.然而,我注意到,在调用转换函数后,带有key=2key=3的瓷砖的动画不会触发,尽管状态更新正确,其他瓷砖的动画也如预期的那样.

App.tsx

import './Index.css';
import { useState, Fragment } from 'react';

function bcls(...parts) {
  return parts.filter(Boolean).join(' ');
}

const initState = [
  { x: 0, y: 0, key: 1, moved: false },
  { x: 2, y: 0, key: 2, moved: false },
  { x: 1, y: 1, key: 3, moved: false },
  { x: 2, y: 1, key: 4, moved: false },
  { x: 3, y: 2, key: 5, moved: false },
];
const transitionState = [
  { x: 0, y: 3, key: 1, moved: true },
  { x: 2, y: 3, key: 4, moved: true },
  { x: 3, y: 3, key: 5, moved: true },
  { x: 2, y: 2, key: 2, moved: true },
  { x: 1, y: 3, key: 3, moved: true },
];

export default function App() {
  const [tiles, setTiles] = useState(initState);

  function transition() {
    setTiles(transitionState);
  }

  function reset() {
    setTiles(initState);
  }

  return (
    <Fragment>
      <button onClick={transition}>transition</button>
      <button onClick={reset}>reset</button>

      <div className="board">
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        {tiles.map((tile) => (
          <div
            key={tile.key}
            className={bcls('tile', tile.moved && 'tile-moved')}
            style={{ '--x': tile.x, '--y': tile.y }}
          >
            {tile.key}
          </div>
        ))}
      </div>
    </Fragment>
  );
}

Index.css

.board {
  --grid: 4;
  --size: 50px;
  --gap: 12px;

  background-color: #8f8b8b;
  padding: var(--gap);
  position: relative;
  display: grid;
  gap: var(--gap);
  grid-template-columns: repeat(var(--grid), var(--size));
  grid-template-rows: repeat(var(--grid), var(--size));
}

.cell {
  background-color: #aaa;
}

.tile {
  background-color: #afe544;
  width: var(--size);
  height: var(--size);
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: calc(var(--y) * (var(--size) + var(--gap)) + var(--gap));
  left: calc(var(--x) * (var(--size) + var(--gap)) + var(--gap));
}

.tile-moved {
  transition: 4000ms ease-in-out;
}

Main.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

这是一张StackBlitz Demo美元.

我希望在调用转换函数时,每个平铺都能平滑地转换到其新位置.这适用于除具有key=2key=3的平铺之外的所有平铺.对于这两个平铺,它们在没有任何动画的情况下跳到其新位置.

推荐答案

这基本上看起来像是一个react 键和数组呈现问题.具有关键字23tiles个元素被移动到tiles数组的末尾,并且因此REACTION从其先前的数组位置(索引1和2)卸载它们,并在当前索引3和4处重新挂载它们.

保持相同的tiles个元素顺序使react 关键点保持相同的顺序,并安装瓷砖元素.只有每个平铺元素的(x,y)"坐标"应该更新.

transitionState值从

// Array elements and keys reordered
const transitionState = [
  { x: 0, y: 3, key: 1, moved: true },
  { x: 2, y: 3, key: 4, moved: true },
  { x: 3, y: 3, key: 5, moved: true },
  { x: 2, y: 2, key: 2, moved: true },
  { x: 1, y: 3, key: 3, moved: true },
];

// Array elements and key order maintained
const transitionState = [
  { x: 0, y: 3, key: 1, moved: true },
  { x: 2, y: 2, key: 2, moved: true },
  { x: 1, y: 3, key: 3, moved: true },
  { x: 2, y: 3, key: 4, moved: true },
  { x: 3, y: 3, key: 5, moved: true },
];

function bcls(...parts) {
  return parts.filter(Boolean).join(' ');
}

const initState = [
  { x: 0, y: 0, key: 1, moved: false },
  { x: 2, y: 0, key: 2, moved: false },
  { x: 1, y: 1, key: 3, moved: false },
  { x: 2, y: 1, key: 4, moved: false },
  { x: 3, y: 2, key: 5, moved: false },
];
const transitionState = [
  { x: 0, y: 3, key: 1, moved: true },
  { x: 2, y: 2, key: 2, moved: true },
  { x: 1, y: 3, key: 3, moved: true },
  { x: 2, y: 3, key: 4, moved: true },
  { x: 3, y: 3, key: 5, moved: true },
];

function App() {
  const [tiles, setTiles] = React.useState(initState);

  function transition() {
    setTiles(transitionState);
  }

  function reset() {
    setTiles(initState);
  }

  return (
    <React.Fragment>
      <but至n onClick={transition}>transition</but至n>
      <but至n onClick={reset}>reset</but至n>

      <div className="board">
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        <div className="cell"></div>
        {tiles.map((tile) => (
          <div
            key={tile.key}
            className={bcls('tile', tile.moved && 'tile-moved')}
            style={{ '--x': tile.x, '--y': tile.y }}
          >
            {tile.key}
          </div>
        ))}
      </div>
    </React.Fragment>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
.board {
  --grid: 4;
  --size: 50px;
  --gap: 12px;

  background-color: #8f8b8b;
  padding: var(--gap);
  position: relative;
  display: grid;
  gap: var(--gap);
  grid-template-columns: repeat(var(--grid), var(--size));
  grid-template-rows: repeat(var(--grid), var(--size));
}

.cell {
  background-color: #aaa;
}

.tile {
  background-color: #afe544;
  width: var(--size);
  height: var(--size);
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  至p: calc(var(--y) * (var(--size) + var(--gap)) + var(--gap));
  left: calc(var(--x) * (var(--size) + var(--gap)) + var(--gap));
}

.tile-moved {
  transition: 4000ms ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="root" />

Typescript相关问答推荐

脉轮ui打字脚本强制执行图标按钮的咏叹调标签-如何关闭

了解TS类型参数列表中的分配

如何在函数参数中使用(或模仿)`success`的行为?

TypeScript类型不匹配:在返回类型中处理已经声明的Promise Wrapper

扩展函数签名中的参数类型,而不使用泛型

Redux—Toolkit查询仅在不为空的情况下添加参数

具有动态键的泛型类型

在不更改类型签名的情况下在数组并集上映射文字

对未到达受保护路由的路由环境做出react

是否可以针对联合类型验证类型属性名称?

确保对象列表在编译时在类型脚本中具有唯一键

避免混淆两种不同的ID类型

创建依赖函数参数的类型

Angular 16将独立组件作为对话框加载,而不进行布线或预加载

顶点堆叠的图表条形图未在正确的x轴上显示

递归生成常量树形 struct 的键控类型

如何在TypeScrip中使用数组作为字符串的封闭列表?

TypeScript:方法获胜';t接受较窄类型作为参数

有没有一种简单的方法可以访问Keyboard Shortcuts JSON文件中列出的每个命令的显示名称(标题)?

当并非所有歧视值都已知时,如何缩小受歧视联盟的范围?