Reactjs 在钩子返回的函数中,状态保持不变
我在玩React和Canvas。我想通过Reactjs 在钩子返回的函数中,状态保持不变,reactjs,react-hooks,Reactjs,React Hooks,我在玩React和Canvas。我想通过requestAnimationFrame设置正方形运动的动画。所以我制作了主要组件来处理画布元素和广场位置的更新: function App() { let canvas = useRef() let square = useSquare(WIDTH / 2, HEIGHT, 2) let update = () => { square.update() requestAnimationFra
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>
</>
}
我想用一个钩子来封装正方形的状态和行为:
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 }
}
函数useSquare(init_x,init_y){
设[x,set_x]=useState(init_x)
让[y,set_y]=useState(init_y)
让[vx,setu vx]=useState(10)
让[vy,set_vy]=useState(-5)
让我们更新=()=>{
设置x(上一个x=>上一个x+vx)
设置y(上一个y=>上一个y+vy)
如果(x=宽度)设置_vx(上一个_vx=>-上一个_vx)
如果(y=高度)设置为(上一个=>-上一个)
}
返回{update,x,y}
}
对我来说似乎很合理。然而,它并没有像预期的那样工作。正方形正在移动,但它不会对与视口边界的碰撞作出响应
如果我将console.log(x,y)
放入update
函数中,我可以看到它以预期的速率启动,但状态没有改变
我不明白,如果状态没有改变,为什么组件能够正确渲染。坦白说,我不知道我做错了什么。也许有人能帮我澄清一下。提前谢谢
PS:我用示例制作了一个codesanbox,回答1:问题是每次运行
requestAnimationFrame
并square.update()
时,您都需要实际创建新的box。在绘制新框架之前,需要清除框架
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()
,这就是为什么您可以看到维度发生了更改
回答3:您正在通过调用
set**
来更新Square
组件中的状态。问题是从useSquare
返回的update
函数是一个闭包,其中x
和y
的值永远不会改变,因此,x=WIDTH
和y=HEIGHT
的条件永远不会成立。下面是一个闭包示例:
设x=1;
功能更新(y){
返回函数(){
console.log(y);//始终为1
};
}
设置间隔(更新(x),1000);
x=2代码>关于闭包是如何工作的,您是对的,但在本例中不是这样的,因为他使用的是通过prev state设置新状态set_x(prev_x=>prev_x+vx)
,所以prev_x
总是最新的。官方文档中的这个例子将解释更多:@TonyNguyen关于功能更新,你是对的。但是更新条件(x=宽度)
和(y=高度)
从来都不是真的,这会导致“正方形正在移动,但它不响应与视口边界的碰撞”的结果。
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;
}