反应状态-更新嵌套数组中对象的属性

时间:2019-06-03 11:03:44

标签: javascript reactjs

我有一个带有界面的React应用,该界面允许用户选择日期和时间段。我有一个维护状态的顶级对象,看起来可能像这样:

this.state = {
  days: [{ 
    date: '12-13-2022',
    time_slots: [{
        start: '10 am',
        end: '11 am',
        selected: false
      },{
        start: '1 pm',
        end: '3 pm',
        selected: false
      }]
    }, {
    date: '12-14-2022',
    time_slots: [{
       start: '10 am',
       end: '11 am',
       selected: false
     }
  }]
}

当用户单击某个时隙时,我想将selected属性更新为true

到目前为止,我已经知道了,但是我认为我正在改变状态,这是一种不好的做法。

slotClicked(day_index, slot_index) {
  let state = this.state.days[day_index].time_slots[slot_index].selected = true;
  this.setState({state});
}

我该如何以高效(就重新渲染而言)和不变的方式更新状态?

4 个答案:

答案 0 :(得分:2)

您必须deep clone数组,以反对其他答案:

slotClicked(day_index, slot_index) {
  // If you prefer you can use lodash method _.cloneDeep()
  const newDays = JSON.parse(JSON.stringify(this.state.days));

  newDays[day_index].time_slots[slot_index].selected = true;
  this.setState({days: newDays});
}

如果您不深度克隆数组,则time_slots数组将通过引用复制,并且对其进行突变将使原始数组处于变异状态。

答案 1 :(得分:0)

您可以将Array.map函数用作

slotClicked(day_index,slot_index){
        let current_state = this.state;
        this.state.days.map((days,days_index) => {
            if(days_index===day_index){
                // console.log("day",days);
                let newSlot = '';
                days.time_slots.map((time_slot,slots_index)=>{
                    if(slots_index===slot_index){
                        // console.log("time",time_slot);
                        newSlot = Object.assign({},time_slot,{selected:true});
                    }
                })
                // console.log("new slot",newSlot);
                days.time_slots[slot_index] = newSlot;
                this.setState({days:current_state},()=>{
                    console.log(this.state);
                });
            }
        });
    }

Demo

答案 2 :(得分:0)

要更新深度嵌套的数据,可以使用https://github.com/debitoor/dot-prop-immutable或类似的方法。在普通的Javascript中,它将像下面这样更加详细

const state = this.state;
const newState = {
    ...state,
    days: [
        ...state.days.slice(0, day_index),
        {
            ...state.days[day_index],
            time_slots: [
                ...state.days[day_index].time_slots.slice(0, slot_index),
                {...state.days[day_index].time_slots[slot_index], selected: true},
                ...state.days[day_index].time_slots.slice(slot_index + 1)
            ]
        },
        ...state.days.slice(day_index + 1)
    ]
}

答案 3 :(得分:-1)

尝试一下,这里我们正在克隆以前的状态并更新新的状态

slotClicked(day_index, slot_index) {
  let newStateDays = [...this.state.days]

  newStateDays[day_index].time_slots[slot_index].selected = true;
  this.setState({days: newStateDays});
}