I have a React project and in short I have a selector that selects projects. When a project is selected it should be set as selected and should start loading it's Revit version in the background (which can be a relatively long process). However, I'm dispatching the selection first then starting the async load. When the load gets finished though, it's still showing the old selection. Here is the dispatcher registration for the component:
const [state, dispatch] = useReducer(reducer, new TaskEditState());
Here is my handler function for the project selector change:
onProjectSelected={p => {
// Attempt first state update here to update the project object on state.
dispatch({
type: TaskEditActions.selectedProjectDestination,
payload: p
});
console.log(p?.Id, state.selectedProjectDestination?.Id);
// Call the async function to load the Revit version
LoadRevitVersion(p, false, true)
.catch(error => onError(error, 'Get Destination Revit Version'));
}}
Here is the code of LoadRevitVersion:
async function LoadRevitVersion(project: ProjectUI, setAsSource: boolean, setAsDestination: boolean, hasCloudModels?: boolean | undefined): Promise<void> {
const payload: {
[k in keyof TaskEditState]?: any;
} = {};
try {
const revitVersion = await projectService.GetProjectRevitVersion(project.HubId, project.Id);
// Once the data is retrieved, update the state again
const index = state.Projects.findIndex(x => x.Id === project.Id);
const newProjects = [...state.Projects];
newProjects[index] = project;
payload.Projects = newProjects;
// I would like to use the project ID on the state object here to make a decision rather than the passed in variables, but this line logs the previous value for project ID instead of the one that should be selected by this point.
console.log(state.selectedProjectDestination?.Id);
if (setAsSource) {
payload.selectedProjectSource = project;
}
if (setAsDestination) {
payload.selectedProjectDestination = project;
}
// This makes the actual call to update the state.
UpdateSaveState(payload);
} catch (error) {
onError(error, 'Load Revit Version');
}
}
So when you select a new project it will start the spinner and log the id's of the existing project and the new one (which are different which is kind of expected at that point since I just dispatched it). However it will spin and load for 15 seconds and then the ID is STILL the old one when logged in the LoadRevitVersion method. I know state updates are async but it seems like it would update during that 15 seconds of loading while I'm doing nothing... I also tried to do a 1 second promise and then call the method to see if that would let React update but same result.
So is there a way to force it to update the state? Or is there something I'm missing here?
To add some context, because this is a long load time it's possible that the user would select a different project while it's loading so I need to see what the selected project is when the version load finishes...
What I would like to happen is when the project selection happens that it would update the state on dispatch so that the project is properly selected in state. Then kick off the Revit version process and when that finishes the state would have the right project selected (and it can do what it needs to from there).