在一种情况下,我有一组数据,其中文件名映射到一组图形线数据。更改复选框后, 它将从地图中删除或添加到地图中(不是JS地图-只是JS对象)。首先,添加操作可以正常工作。 删除操作似乎也起作用,并且从映射中删除文件名后,React状态似乎具有 正确更新。但是,添加其他项目时,react似乎会“复活”一个非常老的状态,该状态代表 曾经添加到地图的所有文件的集合。此行为是由特定的setState()调用引起的,我将突出显示 下面。一直在绕圈调试这一点,并陷入了死胡同。原因状态克隆在console.log()中 呼叫是我发现Chrome console.log呼叫是asynchronous。 我对深度克隆有更多的选择,但是为了消除任何不确定性,我只是深度克隆了一切。
确切的中断是什么。
如果我从this.setState({fetching_data: true},...
中删除呼叫getFIleData()
,那么一切正常。由于某些原因
如果存在该呼叫,它将收到较旧的状态。
如果有人可以阐明这一点,我将不胜感激,因为我已经耗尽了所有想法;)
class ResultsList extends React.Component
{
state = {
fetching_data: false,
// Data on all available files, for which server can provide data
//
// [ {
// date: (5) [mm, dd, hh, mm, ss]
// pm: "pmX"
// fullname: "mm_dd_hh_mm_ss_pmX_TAG"
// tag: "TAG"
// serno: "1234"
// },
// ...
// ]
data : [],
selected_col: "",
// Contents of data files that have been requested from server. If item is in this
// dictionary then is is "selected", i.e. displayed on the graph. When "deselected"
// should be removed from this dictionary.
//
// { filename1 : {
// data: {dataset1: Array(45), dataset2: Array(45), xvalues: Array(45)}
// path: "blah/blah"
// status: 200
// status_str: "ok"
// >>>> These bits are augmented, the above is from server
// FAM_colour: string,
// HEX_color: string,
// <<<<
// },
// filename2 : {
// ...
// }
// }
file_data: {},
file_data_size: 0,
graph: null,
};
createGraphDataSetsFromFileData = (srcFileData) => {
const newGraphDatasets = [];
let idx_prop = 0;
for (var prop in srcFileData) {
if (Object.prototype.hasOwnProperty.call(srcFileData, prop)) {
newGraphDatasets.push(
{
label: 'dataset1_' + prop,
fill: false,
lineTension: 0.5,
backgroundColor: 'rgba(75,192,192,1)',
borderColor: srcFileData[prop].FAM_colour,
borderWidth: 2,
data: srcFileData[prop].data['dataset1'],
}
);
newGraphDatasets.push(
{
label: 'dataset2_' + prop,
fill: false,
lineTension: 0.5,
backgroundColor: 'rgba(75,192,192,1)',
borderColor: srcFileData[prop].HEX_colour,
borderWidth: 2,
data: srcFileData[prop].data['dataset2'],
}
);
idx_prop = idx_prop + 1;
}
}
return newGraphDatasets;
};
getFIleData = (filename) => {
console.log("GETTING OPTICS");
console.log(cloneDeep(this.state));
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// If I remove this setState call then everything works
//
// Display the "fetching data" modal dialog
this.setState({fetching_data: true},
() => {
console.log("££££££ DIALOG SHOW COMPLETED ££££££"); console.log(cloneDeep(this.state));
}
);
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
fetch(`http://${this.SERVER_IP_PORT}/api/v1/get_result/${filename}`)
.then(response => response.json())
.then(json => {
console.log("JSON REPLY RECEIVED")
if (json.status !== 200) {
alert("Failed to fetch results list")
}
else {
const EXPECTED_NO_CYCLES = 45 // Oh so terribly hacky!!!
if (json.data['dataset1'].length === EXPECTED_NO_CYCLES) {
this.setState( (prevState) => {
console.log("JSON SETSTATE PREV STATE AS"); console.log(prevState);
// Clone the file_data map and add the new data to it
let newFileData = cloneDeep(prevState.file_data);
newFileData[filename] = cloneDeep(json); // TODO - FIXME - BAD this is a shallow copy
newFileData[filename].FAM_colour = COLD_COLOURS[prevState.file_data_size % COLD_COLOURS.length];
newFileData[filename].HEX_colour = WARM_COLOURS[prevState.file_data_size % WARM_COLOURS.length];
// Create new graph data from the file_data map
let newGraph = null;
if (newGraph === null) {
newGraph = {
labels : cloneDeep(json.data['xvalues']),
datasets: this.createGraphDataSetsFromFileData(newFileData)
}
}
else {
newGraph = cloneDeep(prevState.graph)
newGraph.labels = cloneDeep(json.data['xvalues']);
newGraph.datasets = this.createGraphDataSetsFromFileData(newFileData)
}
const retval = {
file_data: newFileData,
file_data_size: prevState.file_data_size + 1,
graph : newGraph
};
console.log("------- returning:"); console.log(retval);
return retval;
}, () => {console.log("££££££ OPTICS STAT EUPDATE APPLIED ££££££"); console.log(cloneDeep(this.state)); });
}
else {
alert("Assay test run contains imcomplete data set");
}
}
})
.catch( error => {
alert("Failed to fetch results list: " + error);
})
.finally( () => {
console.log("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@")
this.setState({fetching_data:false},
() => {console.log("££££££ OPTICS STAT FINALLY NOT FETCH APPLIED ££££££"); console.log(cloneDeep(this.state)); });
});
};
//
// THIS FUNCTION IS THE onChange FOR A CHECKBOX and is passed the filename of the item clicked
handleRowSelectionChange = (fullname) => {
if (this.state.file_data.hasOwnProperty(fullname)) {
console.log("CHECKBOX NOT TICKED")
this.setState(
(prevState) => {
// Delete the file from the map
let newFileData = cloneDeep(prevState.file_data);
delete newFileData[fullname];
let rv = {
file_data: newFileData,
file_data_size: prevState.file_data_size - 1,
graph : {
datasets: this.createGraphDataSetsFromFileData(newFileData),
labels: cloneDeep(prevState.graph.labels)
}
}
console.log("______"); console.log(rv);
return rv;
},
() => {
console.log("======== DELETE UPDATE APPLIED =======");
console.log(cloneDeep(this.state));
}
);
}
else {
console.log("CHECKBOX IS TICKED");
this.getFIleData(fullname);
}
}
如果我选择两个文件,则我希望在图中有4个数据集,并且状态反映了这一点:
如果我随后删除这些行,则希望看不到任何图形数据,并且该状态似乎反映了这一点:
引入了旧状态,具体是由
this.setState({fetching_data: true},
() => {
console.log("££££££ DIALOG SHOW COMPLETED ££££££"); console.log(cloneDeep(this.state));
}
);
getFileData函数中的。如果将其删除,则不会引入陈旧状态。