【问题标题】:How is it possible that dynamic components overwrite each other's states?动态组件如何覆盖彼此的状态?
【发布时间】:2019-10-12 01:22:38
【问题描述】:

我创建了基于 Redux 调度的房间对象创建的动态 Room 组件。

{
    rooms && rooms.map((room, index) => {
        const { name, temperature, humidity, timestamp } = room

        return (
            <Col key={index} xs={12} md={6}>
                <Room 
                    index={index}
                    name={name} 
                    temperature={temperature} 
                    humidity={humidity}
                />
            </Col>
        )
    })
}

每个房间的细节都安装正确。我创建了一个函数来维护一个数组中的 10 个对象。但是,当数组传入 Rechart 时,似乎我的组件正在更新相同的状态。

class Room extends Component {
    linechart = () => {
        const { timestamp, temperature, humidity, name } = this.props
        const { chartData } = this.state

        if(chartData.length > 9) chartData.shift()
        chartData.push({
            name, 
            timestamp: moment(timestamp).format('mm:ss'), 
            temperature, 
            humidity})
    }
}

如您所见,组件详细信息已正确显示。然而,chartData 的值被存储在相同的状态,尽管是唯一的组件。

我以 1 秒的间隔运行该函数,日志显示状态正在以 0.5 秒的间隔更新。这意味着两个&lt;Room/&gt; 组件都使用相同的&lt;LineChart/&gt; 组件。 有谁知道如何解决这个问题?

【问题讨论】:

  • 您的 chartData 似乎是由您的组件状态提供的,而不是您的道具。
  • const { chartData } = this.state 应该是const { chartData } = Object.assign({}, this.state)
  • 我认为问题不在于状态的使用。我使用了 1 秒的间隔,日志显示状态正在以 0.5 秒的间隔更新。这意味着两个组件都使用相同的 组件。
  • 我认为你不应该改变状态,就像你对 chartData.shift() 所做的那样。
  • 组件Room有状态吗?如果是,为什么要更改 chartData 而不使用 setState 来存储它?如果没有 setState,则不会调用 render() 来刷新绘图

标签: javascript reactjs react-state-management


【解决方案1】:

为了更新array 中的项目,我建议使用spread syntax。扩展语法通过浅拷贝数组来工作,该数组保留对原始数组的引用,但允许您覆盖其中存储的任何data types。这使数组不可变。

我不确定您从哪里获取数据,但由于您的 rooms 数量有限,因此该数组的结构应该是这样的:

data: [
   { 
     name: "Room1", 
     humidity: 11,
     tempature: 30, 
     timestamp: "Sat May 25 2019 22:23:06 GMT-0700",
   },
   { 
     name: "Room2", 
     humidity: 11,
     tempature: 25, 
     timestamp: "Sat May 25 2019 22:23:06 GMT-0700",
   },
   ...etc
]

然后,您可以简单地将其存储到 state 并在需要时将 map 存储在数组上,并使用传入数据更新其属性。但是,这假设传入数据包含所有rooms。如果您只需要更新rooms 数组中的特定room,则可以将id(或唯一标识它的东西)与传入的新数据id 进行比较。

例如,一个新的更新进来了,但它只是更新Room1,那么我们可以这样做..

传入数据

data: [
  { 
    name: "Room1", 
    humidity: 11,
    tempature: 30, 
    timestamp: "Sat May 25 2019 22:23:06 GMT-0700",
   }
];

当前数据存储在state 中作为“房间”

 this.setState(prevState => ({
      ...prevState, // spread out any previous state not related to "rooms"
      rooms: prevState.rooms.map(room => { // map over "rooms" and pull out each "room" object
        return room.name === data[0].name // if the "room.name" matches incoming data's "name", then...
          ? { ...data[0] } // spread and overwrite it with incoming data
          : room; // else leave the "room" as is
      })
 }));

使用array prototypespopshift 改变存储在state 中的原始数组并且React 不处理对其state 的突变。但是,您可以将 clone room 数组与 Array.from() 或简单地创建一个新数组实例并使用一些数组 prototype 函数改变这个新实例,但是您必须然后重新将此新实例数组设置为 state 以覆盖旧数组——React 可以毫无问题地处理这个问题。它只是没有传播语法那么干净。


工作示例包括spread syntaxArray.prototype 选项以及setInterval

使用idsetInterval 随机更新数组中一项的工作示例

【讨论】:

  • 感谢您指出这一点。似乎问题在于我如何改变状态,我直接 shift() 和 pop() 状态。我克服这个问题的方法是将原始状态传播到另一个变量中并对其进行变异,然后以与您演示的方式相似的方式设置状态。
猜你喜欢
  • 2018-10-05
  • 2020-02-20
  • 2022-11-14
  • 2022-01-18
  • 1970-01-01
  • 2019-06-15
  • 2021-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多