reactjs - 状态在钩子返回的函数中没有改变
问题描述
我在玩 React 和 Canvas。我想为一个正方形的运动设置动画requestAnimationFrame
。所以我制作了主要组件来处理画布元素和更新正方形的位置:
function App() {
let canvas = useRef()
let square = useSquare(WIDTH / 2, HEIGHT, 2)
let update = () => {
square.update()
requestAnimationFrame(update)
}
useEffect(update, [])
return <>
<canvas ref={canvas} width={WIDTH} height={HEIGHT} />
<Renderer.Provider value={() => ref.canvas.getContext("2d")}>
<Square {...square} />
</Renderer.Provider>
</>
}
这Square
是一个组件,但它不返回 JSX。它在以下位置运行绘图操作useEffect
:
function Square({ x, y }) {
let getContext = useContext(Renderer)
useEffect(() => {
let ctx = getContext()
ctx.fillStyle = "#000"
ctx.fillRect(x, y, 10, 10)
}, [x, y])
return null;
}
我想用一个钩子来封装正方形的状态和行为:
function useSquare(init_x, init_y) {
let [x, set_x] = useState(init_x)
let [y, set_y] = useState(init_y)
let [vx, set_vx] = useState(10)
let [vy, set_vy] = useState(-5)
let update = () => {
set_x(prev_x => prev_x + vx)
set_y(prev_y => prev_y + vy)
if (x <= 0 || x >= WIDTH) set_vx(prev_vx => -prev_vx)
else if (y <= 0 || y >= HEIGHT) set_vy(prev_vy => -prev_vy)
}
return { update, x, y }
}
对我来说似乎很合理。但是,它没有按预期工作。Square 正在移动,但它不会响应与视口边界的碰撞。
如果我console.log(x, y)
输入任何一个update
函数,我可以看到它以预期的速率触发,但状态没有改变。
我不明白如果状态没有改变,为什么组件能够正确呈现。坦率地说,我不知道我做错了什么。也许,有人帮我澄清一下。提前致谢。
PS:我用示例https://codesandbox.io/s/xenodochial-jepsen-nfxv6制作了一个codesanbox
解决方案
Answer1:问题是每次requestAnimationFrame
运行时,square.update()
您实际上都是在创建新框。您需要在绘制新框架之前清除框架
import { useContext, useEffect } from "react";
import { Renderer } from "./ctx";
export function Square({ x, y }) {
let getContext = useContext(Renderer);
useEffect(() => {
let ctx = getContext();
// clear before drawing
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
ctx.fillStyle = "#000";
ctx.fillRect(x, y, 10, 10);
}, [x, y]);
return null;
}
检查代码框以进行可视化
这是我在网上找到的一个非常好的系列。一探究竟
答案2: requestAnimationFrame
创建一个循环来调用square.update()
,这就是为什么你可以看到尺寸改变了
Answer3:您正在Square
通过调用更新组件内部的状态set**
推荐阅读
- reactjs - React 将参数从子组件传递给节点元素
- flutter - Flutter Web 支持 didChangeAppLifecycleState 吗?
- go - 如何将导航键添加到 tview?
- asp.net-core - 防止基类属性初始化 JSON.net
- mysql - JOIN 3 表包括不存在为空
- python - 具有多边形边界框的 Tensorflow 对象检测 API 的数据增强
- python - 为什么当密钥不存在时我没有收到密钥错误?
- java - 如何解决 Android 错误“类中的方法 setSupportActionBar?
- ruby-on-rails - 方法定义中的 Ruby Splat 运算符占用更多内存
- java - Java收集集合图