Reputation: 1
I'm using Typescript, React, and Immer to save states, which includes a profile list under which each profile has multiple options (stored as profile.options: Option[]
). I would like to, while saving options, simply make sure the active profile has the correct option data, and then save the active profile.
const { updateProfileList, getProfile } = useProfiles();
const [ activeProfileId, setActiveProfileId ] = useState<string>('dev');
const [ activeOptionId, setActiveOptionId ] = useState<string>("1");
const [ activeProfile, setActiveProfile ] = useImmer(getProfile(activeProfileId));
const [ activeOption, setActiveOption ] = useImmer(getOption(activeOptionId, activeProfileId));
const saveActiveProfile = (id: string = activeProfileId) => {
updateProfileList((draft) => {
const target = draft[draft.findIndex((x)=>x.id === id)] = activeProfile;
target.id = id; // ID of location should not change!!!
});
}
const saveActiveOption = (id: string = activeOptionId) => {
setActiveProfile((draft) => {
const target = draft.options[draft.options.findIndex((x)=>x.id === id)] = activeOption;
target.id = id; // ID of location should not change!!!
});
// saveActiveProfile();
}
However, because of the way the React state works, I suspect that this will not have the intended behavior because saveActiveProfile()
references the activeProfile
state, which will not be updated until after the current render is finished calculating. Is there a better way of doing this besides saving Immer's current(draft) and passing it into the save function?
Edit: Here are the alternative functions:
const saveProfile = (id: string, profile: Profile) => {
updateProfileList((draft) => {
const target = draft[draft.findIndex((x)=>x.id === id)] = profile;
target.id = id; // ID of location should not change!!!
});
}
const saveActiveProfile = (id: string = activeProfileId) => {
saveProfile(id, activeProfile);
}
const saveActiveOption = (id: string = activeOptionId) => {
let intermediateActiveProfile = activeProfile;
updateActiveProfile((draft) => {
const target = draft.options[draft.options.findIndex((x)=>x.id === id)] = activeOption;
target.id = id; // ID of location should not change!!!
intermediateActiveProfile = current(draft);
});
saveProfile(activeProfileId, intermediateActiveProfile);
}
Upvotes: 0
Views: 48
Reputation: 68
Instead of relying on React's asynchronous state updates, you can pass the updated state directly to your save functions.
const saveProfile = (id: string, profile: Profile) => {
updateProfileList((draft) => {
const targetIndex = draft.findIndex((x) => x.id === id);
draft[targetIndex] = { ...profile, id };
});
}
const saveActiveProfile = (updatedProfile?: Profile) => {
const profileToSave = updatedProfile || activeProfile;
saveProfile(activeProfileId, profileToSave);
}
const saveActiveOption = (id: string = activeOptionId) => {
let updatedProfile: Profile;
setActiveProfile((draft) => {
const targetIndex = draft.options.findIndex((x) => x.id === id);
draft.options[targetIndex] = { ...activeOption, id };
updatedProfile = current(draft);
});
saveActiveProfile(updatedProfile);
}
also check out this State as a Snapshot topic in React's documentation, it will help you better to understand, how states work.
Upvotes: 0