Zaid-Ajaj / Feliz

A fresh retake of the React API in Fable and a collection of high-quality components to build React applications in F#, optimized for happiness
https://zaid-ajaj.github.io/Feliz/
MIT License
540 stars 78 forks source link

React 18 in strict mode and useDeferredCallback #489

Open AkosLukacs opened 2 years ago

AkosLukacs commented 2 years ago

Hi! Looks like useDeferredCallback doesn't work with react 18 and strict mode.

Symptoms: upgraded my app to React 18 with strict mode. The UI just hangs, basically nothing happens, and even the network call seems to be cancelled before the server responds. No error thrown, nothing in console. It did work with strict mode & React 17. And does work without strict mode and React 18.

After some digging it looks like the issue might be strict mode in v18 tries to immediately unmount the component and re-mount it. And that triggers the cancellationToken in useDeferredCallback. If I add some logging and an else to the if at https://github.com/Zaid-Ajaj/Feliz/blob/master/Feliz.UseDeferred/UseDeferred.fs#L103 like

            React.useEffectOnce(fun () ->
                React.createDisposable(fun () -> JS.console.log("cancelling..."); cancellationToken.current.Cancel())
            )

            let start = React.useCallbackRef(fun arg ->
                if not cancellationToken.current.IsCancellationRequested
                then Async.StartImmediate(executeOperation arg, cancellationToken.current.Token)
                else JS.console.log("deferred cancelled!", operation)
            )

indeed I get the cancelling and deferred cancelled! message in the console.

Does anybody with more experience with React 18 knows how to solve this? Thanks!

Versions: Fable compiler: 3.7.12

react & react-dom: 18.2.0

Fable.Core (3.7.1) Fable.React (8.0.1) Feliz (1.64) Feliz.UseDeferred (1.4.1)

Zaid-Ajaj commented 2 years ago

Hi there @AkosLukacs, thanks for filing the issue! To be honest, I am not surprised that Feliz.useDeferred doesn't work with React v18.x because they introduced breaking changes with useEffect which useDeferred uses in the implementation.

The current version of Feliz v1.65 and the one you mentioned (v1.64) actually have a strict requirement on React version being: >= 17.0 && < 18.0 as defined in the project settings

    <NpmDependencies>
      <NpmPackage Name="react" Version="&gt;= 17.0.1 &lt; 18.0.0" ResolutionStrategy="Max" />
      <NpmPackage Name="react-dom" Version="&gt;= 17.0.1 &lt; 18.0.0" ResolutionStrategy="Max" />
    </NpmDependencies>

These are npm package requirements

It is expected that upgrading to React v18.x can cause breaking changes. For the time being, consider downgrading to React v17.x until we have updated everything needed: implementations of useEffectOnce(see #480), docs and unit tests