recoil-persist icon indicating copy to clipboard operation
recoil-persist copied to clipboard

Async/await causes a race condition in React

Open bartvanremortele opened this issue 3 years ago • 5 comments

When using useRecoilCallback and setting multiple atoms using the same atomEffect the current implementation breaks. It will cause a race condition getting the current localStorage value because of the async/await that was added to onSet and getState.

This bug causes you to lose state persisted in localStorage

bartvanremortele avatar Apr 16 '21 10:04 bartvanremortele

Could you write a test that recreates this bug? Race conditions are flaky to test, but looking at example code will help explain the issue (which I think I've understood but I'm not 100% sure).

rhys-saldanha avatar Apr 25 '21 23:04 rhys-saldanha

I've encountered this Issue while looking to solve a problem I'm facing on my own app. My use case is that I have a list of preset values that I need to programmatically fill into several atoms of the same family.

Inside the useRecoilCallback, I'm looping through the array given out by the API and using set to fill in the atom value. The problem I was seeing was that only random atoms would get persisted to Local Storage, sometimes with incomplete values. Applying the change submitted by @bartvanremortele also fixed the issue for me, without unintended side-effects from what I could gather so far.

lmartins avatar May 05 '21 09:05 lmartins

Could you write a test that recreates this bug? Race conditions are flaky to test, but looking at example code will help explain the issue (which I think I've understood but I'm not 100% sure).

I'm sorry, I don't have time to write a test. This bug can be easily reproduced by updating two atoms in the same useRecoilCallback.

bartvanremortele avatar May 05 '21 10:05 bartvanremortele

#37 does fix this issue, but two tests fail for the async storage, which is to be expected since with the fix onSet does not take a async function anymore. I didn't go too deep but I don't see an easy solution except maybe adding a asyncStorage boolean flag to the config. 'asyncStorage` could default to true to avoid breaking changes... anyways I'm just brainstorming here, what do you think @polemius ?

stefanoTron avatar May 21 '21 14:05 stefanoTron

I have fixed race condition for synchronize storage (like localStorage) in 2.7.0 version. But the problem still exist for async storage.

polemius avatar May 25 '21 20:05 polemius