编辑-我目前无法为自己的答案投票,但这原来是参考/不变性问题-请参见https://stackoverflow.com/a/60189228/11602055

这个让我完全难住了!

我正在从服务器中获取一些数据并将其应用于状态,但是在setState完成后,我应用于状态的某些属性不会迁移到该状态...

我已经尝试了所有可以想到的事情,我正在从setState的回调中读取最终状态,以确保在setState完成后获取状态,因此与setState本质上无关。

尝试了以下操作-


使用空白对象,将新道具保存到该对象,然后将其返回。
在键的外部循环内的单独setState调用中一次应用每个属性
返回Object.assign({},this.state,data);
返回{... data};
返回{... this.state,... data};
等待setState(...);
setState(数据)


我有几个嵌套的状态属性,但这会影响状态对象的根属性...

请参阅下面的代码/输出/结束状态,例如,注意eventColour尚未通过setState动作传播到最终状态...(对于iconCls同样适用...)

请帮助?...

码:

getJobDetail = async function (){

    // get data from server
    let response = await window.fetch("/event/events?id="+this.props.job,{cache: "no-cache", credentials: "same-origin"});

    // parse returned data
    let data = await response.json();

    // couple of minor data manipulation exercises
    if (data.tempToFeedback!==null){
        data.toFeedback=data.tempToFeedback;
    }
    if (data.tempSwitchNotes!==null){
        data.switchingNotes=data.tempSwitchNotes;
    }
    if (data.editedName!==null){
        data.name=data.editedName;
    }
    if (data.fileList!==null){
        data.fileList=JSON.parse(data.fileList);
    }

    // merge all recieved data onto state
    this.setState(currentState=>{

        for (let key of Object.keys(data)){
            console.log("setting " + key + " from "+currentState[key]+" to " + data[key]);
            currentState[key]=data[key];
        }

        return currentState;
    }
    ,
        ()=>{
            // output new state on callback (doesn't include everything which was merged in...)
            console.log(JSON.parse(JSON.stringify(this.state)))
        }
    )

}


setState期间的控制台输出

setting id from undefined to 214793


setting tnccJobsID from undefined to 214793
 setting startDate from undefined to 2020-02-12T08:00:00.000Z
 setting endDate from undefined to 2020-02-12T09:00:00.000Z
 setting resourceId from undefined to 99921
 setting FKusers from undefined to 99999
 setting previousJob from undefined to null
 setting isInfoBooking from undefined to 0
 setting isCSP from undefined to null
 setting isDAR from undefined to 0
 setting hasStarted from undefined to 0
 setting hasEnded from undefined to 0
 setting isCancelled from undefined to 0
 setting FKtogaGroups from undefined to 12327
 setting currentStep from undefined to 0
 setting adjustedFKjobTypes from undefined to null
 setting FKjobTypes from undefined to 23
 setting lastUpdated from undefined to null
 setting name from undefined to undefined
 setting jobTypeID from undefined to 23
 setting eventType from undefined to Operational Release
 setting eventColor from undefined to orange
 setting eventStyle from undefined to colored
 setting iconCls from undefined to fas fa-plane-departure
 setting weight from undefined to 1
 setting northDesk from undefined to 1
 setting southDesk from undefined to 0
 setting switchOutState from undefined to 1
 setting feedbackState from undefined to 1
 setting feedbackRequired from undefined to 0
 setting demandAtRisk from undefined to null
 setting demandAtRiskApproved from undefined to null
 setting runwaySteps from undefined to [object Object],[object Object],[object Object],[object Object],[object Object]
 setting startStep from undefined to 4
 setting endStep from undefined to 5
 setting fileList from undefined to
 setting outageList from undefined to [object Object]
 setting toFeedback from undefined to undefined
 setting switchingNotes from undefined to undefined


回调中读出的最终状态

updateData: {}
fileDrawer: null
fileUploading: null
showJobDetailModal: false
id: 214793
tnccJobsID: 214793
startDate: "2020-02-12T08:00:00.000Z"
endDate: "2020-02-12T09:00:00.000Z"
resourceId: 99921
FKusers: 99999
previousJob: null
isInfoBooking: 0
isCSP: null
isDAR: 0
hasStarted: 0
hasEnded: 0
isCancelled: 0
FKtogaGroups: 12327
currentStep: 0
adjustedFKjobTypes: null
FKjobTypes: 23
lastUpdated: null
jobTypeID: 23
eventType: "Operational Release"
eventStyle: "colored"
weight: 1
northDesk: 1
southDesk: 0
switchOutState: 1
feedbackState: 1
feedbackRequired: 0
demandAtRisk: null
demandAtRiskApproved: null
runwaySteps: (5) [{…}, {…}, {…}, {…}, {…}]
startStep: 4
endStep: 5
fileList: []
outageList: [{…}]
__proto__: Object


图像格式也是如此!

Code

setState Output

state as read in callback

其中包含数据的代码演示版本:

    import React, { Component } from 'react';


export const JobView = class JobView extends React.PureComponent{



    render(){


            return null;

    }

}


export const JobDetails = class JobDetails extends React.Component{
    constructor(props){
        super(props);
        this.state={
            // jobData:null,
            updateData:{},


        }


        this.getJobDetail = this.getJobDetail.bind(this);

        this.setState = this.setState.bind(this);


    }

    componentDidMount(){





        this.getJobDetail();


        }


    getJobDetail = async function (){

        // get data from server
        // let response = await window.fetch("/event/events?id="+this.props.job,{cache: "no-cache", credentials: "same-origin"});

        // parse returned data
        // let data = await response.json();
        let data = JSON.parse('{"id":5267,"tnccJobsID":5267,"startDate":"2020-02-12T08:00:00.000Z","endDate":"2020-02-12T09:00:00.000Z","resourceId":99921,"FKusers":99999,"previousJob":null,"isInfoBooking":0,"isCSP":null,"isDAR":0,"hasStarted":null,"hasEnded":null,"isCancelled":null,"FKtogaGroups":2830,"currentStep":1,"adjustedFKjobTypes":null,"FKjobTypes":1,"lastUpdated":"2020-01-21T22:30:43.000Z","name":"OCKER HILL 132KV BUS SECTION 120 .","jobTypeID":1,"eventType":"Operational Release","eventColor":"orange","eventStyle":"colored","iconCls":"fas fa-plane-departure","weight":1,"northDesk":1,"southDesk":0,"switchOutState":1,"feedbackState":1,"feedbackRequired":0,"demandAtRisk":null,"demandAtRiskApproved":null,"runwaySteps":[{"step":1,"active":{"icon":"loading","text":"Planning"},"isLast":false,"completed":{"icon":"bars","text":"Planned"}},{"step":2,"active":{"icon":"loading","text":"Negotiating TSC"},"isLast":false,"completed":{"icon":"file-done","text":"TSC Recieved"}},{"step":3,"active":{"icon":"loading","text":"Awaiting Allocation"},"isLast":false,"completed":{"icon":"user","text":"Allocated"}},{"step":4,"active":{"icon":"loading","text":"Waiting to Start"},"isLast":false,"completed":{"icon":"user","text":"Started"}},{"step":5,"active":{"icon":"loading","text":"Switching In Progress"},"isLast":false,"completed":{"icon":"api","text":"Switched"}},{"step":6,"active":{"icon":"loading","text":"Releasing To Safety"},"isLast":true,"completed":{"icon":"check","text":"Released To Safety"}}],"startStep":4,"endStep":6,"fullHistory":[{"time":"2019-11-23T22:58:44.000Z","entryTo":"No","entryFrom":0,"changedBy":"System","message":"hasEnded Changed"},{"time":"2019-11-23T22:58:44.000Z","entryTo":"No","entryFrom":0,"changedBy":"System","message":"hasStarted Changed"},{"time":"2019-11-23T22:58:44.000Z","entryTo":"No","entryFrom":0,"changedBy":"System","message":"isCancelled Changed"},{"time":"2019-11-25T23:03:12.000Z","entryTo":"No","entryFrom":0,"changedBy":"System","message":"hasEnded Changed"},{"time":"2019-11-25T23:03:12.000Z","entryTo":"No","entryFrom":0,"changedBy":"System","message":"hasStarted Changed"},{"time":"2019-11-25T23:03:12.000Z","entryTo":"No","entryFrom":0,"changedBy":"System","message":"isCancelled Changed"},{"time":"2019-11-28T22:59:03.000Z","entryTo":"No","entryFrom":0,"changedBy":"System","message":"hasEnded Changed"},{"time":"2019-11-28T22:59:03.000Z","entryTo":"No","entryFrom":0,"changedBy":"System","message":"hasStarted Changed"},{"time":"2019-11-28T22:59:03.000Z","entryTo":"No","entryFrom":0,"changedBy":"System","message":"isCancelled Changed"},{"time":"2020-01-13T22:39:10.000Z","entryTo":0,"entryFrom":null,"changedBy":"System","message":"isDAR Changed"}],"fileList":"[]","outageList":[]}');

        // console.log(JSON.stringify(data));
        // couple of minor data manipulation exercises
        if (data.tempToFeedback!==null){
            data.toFeedback=data.tempToFeedback;
        }
        if (data.tempSwitchNotes!==null){
            data.switchingNotes=data.tempSwitchNotes;
        }
        if (data.editedName!==null){
            data.name=data.editedName;
        }
        if (data.fileList!==null){
            data.fileList=JSON.parse(data.fileList);
        }

        // merge all recieved data onto state
        await this.setState((currentState,props)=>{
            let newState = {}
            for (let key of Object.keys(data)){
                console.log("setting " + key + " from "+currentState[key]+" to " + data[key]);
                newState[key]=data[key];
            }
            console.log(newState);
            return newState;
        }


        ,
            ()=>{
                // output new state on callback (doesn't include everything which was merged in...)

                console.log(this.state);
            }
        )

    }





    render(){
        return JSON.stringify(this.state);
    }

}

最佳答案

原来我很傻!但是对于遇到此问题的其他人,我的渲染函数中有一部分是这样的:

constructor(props){
  super(props);
  this.state={prop1:"first value"};
}
render(){
  console.log(JSON.parse(JSON.stringify(this.state.prop1))) // "first value"
  let easyToAccessState = this.state;
  easyToAccessState.prop1 = "another value";
  console.log(JSON.parse(JSON.stringify(this.state.prop1))) // "another value"
}


为了避免这种情况,请在easyToAccessState变量中创建状态副本:

render(){
  console.log(JSON.parse(JSON.stringify(this.state.prop1))) // "first value"
  let easyToAccessState = {...this.state}; // COPIES STATE
  easyToAccessState.prop1 = "another value";
  console.log(JSON.parse(JSON.stringify(this.state.prop1))) // "first value"
}


显然,理想情况下,在渲染期间不应对任何内容进行任何更改……这是我要摆脱的事情,并且将对prop1的重新计算进行移动,以使其正确进入状态并首先正确使用它……

这些东西被发送给我们测试...不变性和引用!

09-30 13:25
查看更多