Fix concurrency bug in results view
In the results view, `setState` was used to set some state, and then `loadResults` was called to set some other state. However, `setState` is asynchronous, so the `this.state` in `loadResults` was not the state that was set before the call. This commit fixes it by combining the two `setState` calls into one. The logic was hard to follow, so I'm not sure if this is the correct fix. The `shouldKeepOldResultsWhileRendering` state seems to be unnecessary now since everything is being done in `setState` call, but I'm not sure about that.
This commit is contained in:
@@ -104,7 +104,6 @@ export class ResultsApp extends React.Component<
|
|||||||
queryPath: msg.queryPath,
|
queryPath: msg.queryPath,
|
||||||
});
|
});
|
||||||
|
|
||||||
void this.loadResults();
|
|
||||||
break;
|
break;
|
||||||
case "showInterpretedPage": {
|
case "showInterpretedPage": {
|
||||||
const tableName =
|
const tableName =
|
||||||
@@ -141,7 +140,6 @@ export class ResultsApp extends React.Component<
|
|||||||
queryName: msg.queryName,
|
queryName: msg.queryName,
|
||||||
queryPath: msg.queryPath,
|
queryPath: msg.queryPath,
|
||||||
});
|
});
|
||||||
void this.loadResults();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "resultsUpdating":
|
case "resultsUpdating":
|
||||||
@@ -164,31 +162,61 @@ export class ResultsApp extends React.Component<
|
|||||||
|
|
||||||
private updateStateWithNewResultsInfo(resultsInfo: ResultsInfo): void {
|
private updateStateWithNewResultsInfo(resultsInfo: ResultsInfo): void {
|
||||||
this.setState((prevState) => {
|
this.setState((prevState) => {
|
||||||
const stateWithDisplayedResults = (
|
if (resultsInfo === null) {
|
||||||
displayedResults: ResultsState,
|
if (prevState.isExpectingResultsUpdate) {
|
||||||
): ResultsViewState => ({
|
// Display loading message
|
||||||
displayedResults,
|
return {
|
||||||
isExpectingResultsUpdate: prevState.isExpectingResultsUpdate,
|
displayedResults: {
|
||||||
nextResultsInfo: resultsInfo,
|
resultsInfo: null,
|
||||||
});
|
results: null,
|
||||||
|
errorMessage: "Loading results…",
|
||||||
|
},
|
||||||
|
isExpectingResultsUpdate: prevState.isExpectingResultsUpdate,
|
||||||
|
nextResultsInfo: resultsInfo,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// No results to display
|
||||||
|
return {
|
||||||
|
displayedResults: {
|
||||||
|
resultsInfo: null,
|
||||||
|
results: null,
|
||||||
|
errorMessage: "No results to display",
|
||||||
|
},
|
||||||
|
isExpectingResultsUpdate: prevState.isExpectingResultsUpdate,
|
||||||
|
nextResultsInfo: resultsInfo,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!prevState.isExpectingResultsUpdate && resultsInfo === null) {
|
let results: Results | null = null;
|
||||||
// No results to display
|
let statusText = "";
|
||||||
return stateWithDisplayedResults({
|
try {
|
||||||
resultsInfo: null,
|
const resultSets = this.getResultSets(resultsInfo);
|
||||||
results: null,
|
results = {
|
||||||
errorMessage: "No results to display",
|
resultSets,
|
||||||
});
|
database: resultsInfo.database,
|
||||||
|
sortStates: this.getSortStates(resultsInfo),
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
let errorMessage: string;
|
||||||
|
if (e instanceof Error) {
|
||||||
|
errorMessage = e.message;
|
||||||
|
} else {
|
||||||
|
errorMessage = "Unknown error";
|
||||||
|
}
|
||||||
|
|
||||||
|
statusText = `Error loading results: ${errorMessage}`;
|
||||||
}
|
}
|
||||||
if (!resultsInfo || !resultsInfo.shouldKeepOldResultsWhileRendering) {
|
|
||||||
// Display loading message
|
return {
|
||||||
return stateWithDisplayedResults({
|
displayedResults: {
|
||||||
resultsInfo: null,
|
resultsInfo,
|
||||||
results: null,
|
results,
|
||||||
errorMessage: "Loading results…",
|
errorMessage: statusText,
|
||||||
});
|
},
|
||||||
}
|
nextResultsInfo: null,
|
||||||
return stateWithDisplayedResults(prevState.displayedResults);
|
isExpectingResultsUpdate: false,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,49 +231,6 @@ export class ResultsApp extends React.Component<
|
|||||||
return [resultSet];
|
return [resultSet];
|
||||||
}
|
}
|
||||||
|
|
||||||
private async loadResults(): Promise<void> {
|
|
||||||
const resultsInfo = this.state.nextResultsInfo;
|
|
||||||
if (resultsInfo === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let results: Results | null = null;
|
|
||||||
let statusText = "";
|
|
||||||
try {
|
|
||||||
const resultSets = this.getResultSets(resultsInfo);
|
|
||||||
results = {
|
|
||||||
resultSets,
|
|
||||||
database: resultsInfo.database,
|
|
||||||
sortStates: this.getSortStates(resultsInfo),
|
|
||||||
};
|
|
||||||
} catch (e) {
|
|
||||||
let errorMessage: string;
|
|
||||||
if (e instanceof Error) {
|
|
||||||
errorMessage = e.message;
|
|
||||||
} else {
|
|
||||||
errorMessage = "Unknown error";
|
|
||||||
}
|
|
||||||
|
|
||||||
statusText = `Error loading results: ${errorMessage}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState((prevState) => {
|
|
||||||
// Only set state if this results info is still current.
|
|
||||||
if (resultsInfo !== prevState.nextResultsInfo) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
displayedResults: {
|
|
||||||
resultsInfo,
|
|
||||||
results,
|
|
||||||
errorMessage: statusText,
|
|
||||||
},
|
|
||||||
nextResultsInfo: null,
|
|
||||||
isExpectingResultsUpdate: false,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private getSortStates(
|
private getSortStates(
|
||||||
resultsInfo: ResultsInfo,
|
resultsInfo: ResultsInfo,
|
||||||
): Map<string, RawResultsSortState> {
|
): Map<string, RawResultsSortState> {
|
||||||
|
|||||||
Reference in New Issue
Block a user