Javascript 如何在react应用程序的上下文中存储类实例和管理状态
我正在使用这个矩形类Javascript 如何在react应用程序的上下文中存储类实例和管理状态,javascript,reactjs,object,state,Javascript,Reactjs,Object,State,我正在使用这个矩形类 class Rectangle { constructor(x, y, width, height, color, hasCollision = false, kills = false) { this.A = new Point(x, y) this.B = new Point(x + width, y) this.C = new Point(x + width, y + height) this.D = new Point(x, y
class Rectangle {
constructor(x, y, width, height, color, hasCollision = false, kills = false) {
this.A = new Point(x, y)
this.B = new Point(x + width, y)
this.C = new Point(x + width, y + height)
this.D = new Point(x, y + height)
this.center = new Point(x + width / 2, y + height / 2)
this.width = width
this.height = height
this.color = color
this.hasCollision = hasCollision
this.kills = kills
}
get vertices() {
const { A, B, C, D } = this
return {
A,
B,
C,
D
}
}
get x() {
return this.A.x
}
get y() {
return this.A.y
}
static translate(rectangle, vector) {
for (let vertice of Object.values(rectangle.vertices)) {
vertice.translate(vector)
}
rectangle.center.translate(vector)
}
translate(vector) {
Rectangle.translate(this, vector)
}
hasUserFallenInTrap(user) {
if (circleIntersectsRectangle(user, this) && this.kills) {
return true
}
return false
}
display(ctx, useOwnColor = true) {
const { x, y, width, height } = this
if (useOwnColor) {
ctx.fillStyle = this.color
? this.color.hexString
: this.kills
? 'red'
: '#000000'
}
ctx.fillRect(x, y, width, height)
}
}
我需要在数组中存储一组矩形,以便在画布中显示它们(包装在React组件中)。组件不会更新每一帧,我在画布上使用自己的绘图功能 :
// Here is the component
class Game extends React.Component {
constructor(props) {
super(props)
const world = loadMap('world1')
this.state = {
currentWorld: world,
users: {},
user: new User(
world.spawn.center.x,
world.spawn.center.y,
12,
Color.random(),
'',
world.spawn
)
}
this.canvas = React.createRef()
this.ctx = null
}
componentDidMount() {
const { user } = this.state
server.userConnects(user)
openConnection()
this.ctx = this.canvas.current.getContext('2d')
setPointerLock(this.canvas.current, this.mouseMoved)
this.request = window.requestAnimationFrame(this.draw)
}
componentWillUnmount() {
closeConnection()
window.cancelAnimationFrame(this.request)
}
shouldComponentUpdate() {
return false
}
updateUserID = id => {
this.setState({ u })
}
mouseMoved = event => {
const { currentWorld, user } = this.state
const displacement = new Vector(
event.movementX / pixelRatio,
event.movementY / pixelRatio
)
user.translate(displacement)
resolveWorldBordersCircleCollision(user)
for (const w of currentWorld.walls) {
if (w.hasCollision) stepCollisionResolve(user, w)
}
server.updateUserPosition(user)
}
draw = () => {
const { currentWorld, users, user } = this.state
this.request = window.requestAnimationFrame(this.draw)
this.ctx.clearRect(0, 0, WIDTH, HEIGHT)
this.ctx.fillText(fpsCounter.fps, 1000, 20)
currentWorld.walls.forEach(w => {
if (w.hasCollision && resolveCollisionCircleRectangle(user, w)) {
server.updateUserPosition(user)
}
w.display(this.ctx)
})
currentWorld.movableWalls.forEach(w => {
w.walkPath()
if (w.hasCollision && resolveCollisionCircleRectangle(user, w)) {
server.updateUserPosition(user)
}
w.display(this.ctx)
})
currentWorld.traps.forEach(t => {
t.display(this.ctx)
if (t.hasUserFallenInTrap(user)) {
user.kill()
server.updateUserPosition(user)
}
})
user.display(this.ctx, false)
Object.values(users)
.filter(u => u.id !== user.id)
.forEach(u => {
u.display(this.ctx, true)
})
}
render() {
return (
<>
<canvas ref={this.canvas} id="canvas" width={WIDTH} height={HEIGHT} />
</>
)
}
}
但是如果矩形处于组件状态,我就不能这样做。
调用rect.translate
将直接改变状态
每次更新状态时创建一个新对象完全违背了使用此类的目的 .
使用对象分解将创建一个简单的新对象,因此我将无法再调用它的display
方法 :
// changing a single rectangle for example
const { rectangles } = this.state
this.setState({ rectangles: [...rectangles.splice(0,index) , { ...rectangles[index], x: rectangles[index].x + 10, y: rectangles[index].y + 10 }, ...rectangles.splice(index + 1)]
在任何react组件之外使用数组似乎是唯一的解决方案,但对于react应用程序来说,这两种方法都不太令人满意
我没有办法管理我的应用程序的状态
有没有更好的方法来存储这个矩形
实例数组?
或者在react中使用这种对象设计是根本不可能的?困难的部分是要弄清楚是否真的需要可变性(例如,出于性能原因),或者在对react进行更多思考(以及睡个好觉)之后,状态是否可以在react中生存
如果需要可变性,应用程序的这一部分可以在React之外作为一个(状态可以存在于DOM或一些将更新DOM的命令性代码中)存在
React的父组件可以通过使用ref
(请参阅上面的文章)访问out-of-React可变状态(从事件处理程序或生命周期方法)。一个使用useRef
hook的简化示例:
const rndColor=()=>`rgb(${Array.from(Array(3)).map(()=>Math.random()*255.join(','))`
常量应用=()=>{
const canvasRef=React.useRef()
常量handleClick=()=>{
//-->rect.translate({x:10,y:20})可以在此处调用“每次更新状态时创建一个新对象完全违背了使用此类的目的”-为什么?让translate
返回一个新实例听起来非常有用。我没有想到这一点,但我正在每秒刷新画布60次。每次我移动一个矩形时创建一个新实例的性能似乎非常高。你是自己制作动画帧,还是试图让React来制作动画画布重绘?在这种情况下,确实没有理由将它们置于状态
——您不需要对它们做出反应。只需将矩形数组直接存储在实例上,就像您使用.canvas
或.ctx
所做的那样。您还可以让矩形根据用例处理自己的绘图。例如c画布绘制时,矩形上的所有更新方法都会更新,如果需要,让矩形绘制/移动/调整大小/平移。这样,逻辑就更符合形状的目的
// changing a single rectangle for example
const { rectangles } = this.state
this.setState({ rectangles: [...rectangles.splice(0,index) , { ...rectangles[index], x: rectangles[index].x + 10, y: rectangles[index].y + 10 }, ...rectangles.splice(index + 1)]