question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Undocumented breaking change in v0.6.0?

See original GitHub issue

Hey! Version 0.6.0 changed the effect execution order, and I think this is a potentially breaking change that’s not called out in the change log. Regardless, my question is how to get the old behaviour back?

Looking at the CodeSandbox, notice that in version 0.5.2, the console shows logs in the correct order (first and second). However, from version 0.6.0 and up, the console shows logs in the reverse order (second and first).

The particular issue I ran into is that onSet() callback is updating the authorisation token used in requests. These are called inside a component based on the existence of the atom value. So pre-0.6.0, we could safely assume that when the value exists, the token is set, but since 0.6.0, it is no longer true and I end up triggering requests without correct authorisation tokens.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:1
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
drarmstrcommented, Feb 3, 2022

Yes, this change is listed in the release notes related to Recoil updates now occurring earlier. Setting Recoil state now happens right away instead of being queued for the end of the batch. This allows React and Recoil state changes to stay in sync and continues to align with React compatibility for concurrent rendering and transitions. You should not currently make assumptions about the relative ordering of atom effect observers and React effects, which is not documented.

The onSet() handler was not originally intended to be used to monitor and transform all atom set operations. For example, it is currently only called at the end of a batch, so it is possible that some set values may be skipped if they are collapsed in the same batch. There would also be complications if there are multiple atom effects attempting the same pattern or there were cascading onSet() handlers. I played with it a bit, and it would conceivably be possible for the semantics of onSet() to change to allow this usage… but we would really want to think of the ramifications of this, particularly for transactions and multi-versioned concurrent updates.

To achieve the behavior you want another pattern may be safer and more straightforward. I’m not sure the semantics of your requests or tokens, but consider a wrapper hook for the request atom:

function useMyRequestAtom() {
  const [request, setRequest] = useRecoilState(requestAtom);
  return [
    request,
    newRequest => {
      setRequest({
        request: newRequest,
        token: getNewToken(),
      });
    },
  ];
}

Or, it may be simpler/safer to use selectors to attach tokens to requests:

const requestAtom = atom({
  key: 'Request',
  default: null,
});

// Intermediate selector with request and token may not be necessary, depending on your usage.
const requestWithTokenSelector = selector({
  key: 'RequestWithToken',
  get: ({get}) => ({
    request: get(requestAtom),
    token: getNewToken(),
  }),
});

const querySelector = selector({
  key: 'Query',
  get: ({get}) => {
    const {request, token} = get(requestWithTokenSelector);
    return fetchQuery(request, token);
  },
});

Depending on the exact behavior needed a slightly different pattern may be appropriate, but likely something using the above techniques would be safer than trying to monitor and transform all atom set operations with onSet().

0reactions
mrluboscommented, Feb 4, 2022

Thanks @drarmstr ! That was very straightforward. I’ll add more details in case anyone else runs into the same problem, or if you know a cleaner solution.

I ended up implementing the selector roughly as follows:

const requestSelector = selector({
  key: 'RequestWithToken',
  get: () => requestAtom,
  set: ({ set }, token) => {
    setTokenAsSideEffect(token);
    set(requestAtom, token);
  },
});

Then pretty much every component works with this selector. There is one exception, and that’s the component responsible for resetting the atom state on logout. Very clean!

The other change I had to do was add an effect to requestAtom to call setTokenAsSideEffect() with the initial value. This is because on load, we don’t call set() on requestSelector, so there was nothing setting the initial state. This effect replaces the “sync” effect which was causing incorrect state outlined in this issue.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Fennel documentation for v0.6.0
Fix a bug where global mangling would break when used with an environment. Fix a bug where globals tracking would lose track of...
Read more >
Changelog | Meteor API Docs
Summary of breaking changes; Migration steps; Breaking changes ... The undocumented environment variable DDP_DEFAULT_CONNECTION_URL behavior has changed.
Read more >
Southwest Land Border Encounters
For a breakdown of encounters by USBP Sector and OFO Field Office, visit Southwest Land Border Encounters (By Component). To access the data ......
Read more >
Installing the Solidity Compiler — Solidity 0.8.17 documentation
Despite our best efforts, they might contain undocumented and/or broken changes that will not become a part of an actual release.
Read more >
Illegal Aliens in Federal, State, and Local Criminal Justice ...
This report describes the characteristics of illegal aliens in the criminal justice system at Federal, State and local levels. Abstract. The report uses...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found