Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在react应用程序的上下文中存储类实例和管理状态_Javascript_Reactjs_Object_State - Fatal编程技术网

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)]