javascript - 在动画更新时从父组件更新子组件 DOM
问题描述
我设置了以下 Codepen 以供参考: Animate React Ref GSAP
我有一个我正在处理的 React 项目,例如,其中存在 2 个组件:一个 Pitch(如在足球场中)和一个 Player。Pitch 是 Player 的父级,aforwardRef()
用于管理可能在 Pitch 组件本身的球场上的每个球员的动画。
您还将在 Player 组件中看到render()
。SVG 包含一个<g id="Position">...</g>
分组,其中圆圈的位置应随着动画的进行而更新。这是我不知所措的地方。
在这个项目中,我使用 GSAP 来管理动画,但它实际上可以是任何动画库 - 如果我要通过状态更改重新渲染 Player 组件来制作动画,甚至可能没有,但性能可能会令人担忧。GSAPonUpdate
为其timeline.to()
函数调用提供了一个选项。可以从 ref 读取 SVG 的位置值,但尝试使用ReactDOM.findDOMNode(component)
[reference]从父级更新其 DOM 是不好的做法。
因此,我的问题真的归结为:
- 如果直接从父元素影响子元素的 DOM 不是最佳实践(我相信根据严格的 ESLint,从功能组件中甚至不可能),那么我应该如何管理它?
- 动画应该在孩子身上触发吗?
- 或者,我应该以某种方式从父母的状态重新渲染?
如果我还没有完全说清楚,请告诉我,我会尽力澄清任何事情或一切!
解决方案
在设计 React 组件时,您应该遵循一些关键原则。
- 状态是事实的来源,所以你的组件如何显示(渲染)完全取决于状态(&prop)中的数据如何。永远不应该出现一种状态可以以不同方式呈现的情况。
考虑到这一点,拥有此代码timeline.to(playerRef.current, { x: 0, y: 0, duration: 2 });
并不是真正的“反应方式”,因为它不会将玩家位置存储到状态中,而是使用另一件事(gsap)来操纵事物的显示方式(x,y 位置)
这是更多的反应方式
// Pitch
const Pitch = () => {
const defaultPosition = { x: 210, y: 136 }
const [playerPosition, setPlayerPosition] = useState(defaultPosition);
const playMe = () => {
setPlayerPosition({ x: 0, y: 0 });
};
const resetMe = () => {
setPlayerPosition(defaultPosition);
};
return (
<>
<button type="button" onClick={playMe}>Play</button>
<button type="button" onClick={resetMe}>Reset</button>
<hr />
<svg width="420px" height="272px" viewBox="0 0 420 272">
<g id="Pitch">
<rect id="Pitch-Background" fill="#409D41" x="0" y="0" width="420" height="272"></rect>
</g>
<Player position={playerPosition} />
</svg>
</>
);
}
所以下一个问题将是“我们如何管理动画?”
React Component 中 90% 的动画,你会想要在状态之间做动画。状态 A 到状态 B 之间的转换。
在 React 中管理动画方面,我可以分为 3 组。
- 从预定义状态 A 到预定义状态 B 的转换(例如 div open x = 200 到 div close x = 0)
- 动态从状态 A 转换到状态 B(例如移动到发生鼠标单击的位置)
- 状态 A 到状态 B 之间的时间线/动画序列(例如,三个元素必须一个接一个地进行动画处理才能完成整个动画序列)
如果您的用例属于 1. 那么 csstransition
就是您的答案。
如果您的用例属于 2. 那么 csstransition
可以是您的答案,也可以是一些动画库,例如react-motion
, react-spring
,framer motion
等。
如果您的用例属于 3。那么 GSAP 时间线就是您的大男孩。但是有一定的方法可以写这个。在这一点上,我不会详细介绍。
同样,在您的示例中......假设它是 2。(从状态 A 动态转换到状态 B)。我们可以用 css 解决这个问题transition
。
const Player = ({ position }) => {
return (
<g
style={{ transition: `all 1s ease-out` }}
transform={`translate(${newPosition.x},${newPosition.y})`}
>
<circle id="Oval" fill="#FF0000" cx="23" cy="39" r="19.5"></circle>
</g>
}
这是我所描述的工作代码。 https://codepen.io/Doppy/pen/XWjNmdB
PS。我在示例中添加了如何让玩家移动到鼠标点击的位置:)
祝你有美好的一天!
推荐阅读
- spring-boot - 在 Spring Security 中配置 antMatchers
- java - Discord 机器人异常重复
- javascript - 如何检测脚本是直接调用还是通过带有 yargs 的节点调用?
- django - 'ws = cat.get_workspace('rake_ereke')' 代码在本地工作,但在服务器上引发无法建立新连接:[Errno 110]
- php - 来自 AJAX 请求的分页无法正常工作——Laravel 5.6
- c++ - 从编译时已知的日历日期创建 `std::chrono::time_point`
- javascript - 如何在 javascript 中的地理定位应用程序中实现搜索功能
- apache - htaccess 使用参数重定向到新域
- javascript - 在 querySelectorAll() 中插入变量不起作用
- javascript - 当我使用 jquery 滚动窗口时试图获得警报