Skip to content
This repository has been archived by the owner on Jan 1, 2025. It is now read-only.

render twice on component mount (useRecoilValue, useRecoilState) no StrictMode #307

Closed
NikitaBazhenov opened this issue Jun 11, 2020 · 34 comments

Comments

@NikitaBazhenov
Copy link

Hello,

I am really excited about this project, I've played around and just notice that my component was rendered twice after it mounted even without StrictMode(in production) #75

I've created a small example without StrictMode enabled on code sandbox:
https://codesandbox.io/s/recoil-itit-double-render-jzbun

just wondering what I am doing wrong
I appreciate any help!

@Shmew
Copy link

Shmew commented Jun 11, 2020

I've also noticed it always renders twice on initialization of a component that subscribes to a recoil value.

@el1s7
Copy link

el1s7 commented Jun 11, 2020

Just noticed that it rendered 4 times on initalization of a component for me.
And it renders twice on every update. How can this affect performance and user experience?

@NikitaBazhenov
Copy link
Author

@elis-k probably you are run your app in development env and you are using <React.StrictMode> on root level in your app, please check this issue related to StrictMode: facebook/react#15074
so if you are in StrictMode you will see 4 times rendering in dev (2 times React.StrictMode + 2 times useRecoilValue) and in production build, StrictMode is doesn't work, so it will be 2 times because of useRecoilValue) 😞

@Shmew
Copy link

Shmew commented Jun 11, 2020

Yeah I've tested renders and it's only on the initialization, after that it's a single render per committed update that's subscribed by the component.

@semvis123
Copy link

Does someone have a fix for this? it breaks my code.

@drarmstr
Copy link
Contributor

@semvis123 - How is this breaking your code?

@semvis123
Copy link

@drarmstr It causes my function to run twice, which is not good for performance, and if API calls are placed inside those get called twice.

@drarmstr
Copy link
Contributor

React render functions shouldn’t have side effects, so this should only be an optimization not a correctness issue. That’s why the React strict mode does extra renders to help test for side effects.

@semvis123
Copy link

Where should I put my function, so it only runs once?

@drarmstr
Copy link
Contributor

Check out ‘useEffect()’ for side effects.

@semvis123
Copy link

Thanks, I will definitely try that.

@drarmstr
Copy link
Contributor

drarmstr commented Sep 9, 2020

Recent optimizations should remove the extra render from Recoil during mount. This should be available in master; we're working on fixing an issue and then it will be release with 0.0.11.

@smith-chris
Copy link

Hey, I believe this is still happening with lates 0.1.1 and 0.0.11 mentioned above. React.StrictMode disabled ofc. Any ideas?

Also forked sandbox from OP shows that the issue is still there: https://codesandbox.io/s/recoil-itit-double-render-forked-pr502?file=/package.json

@drarmstr
Copy link
Contributor

drarmstr commented Nov 2, 2020

@smith-chris - Are you using the experimental React version with Concurrent Mode support?

@salvoravida
Copy link
Contributor

Issue CodeSandBox
https://codesandbox.io/s/recoil-legacy-double-render-30bjc

Fix CodeSandBox
https://codesandbox.io/s/recoil-legacy-double-render-fixed-2oxfj

@smith-chris
you can test the pr with package '@salvoravida/recoil' 0.1.3

@salvoravida
Copy link
Contributor

@drarmstr please can you check the PR?

the problem is on _LEGACY implementation

@drarmstr
Copy link
Contributor

drarmstr commented Jan 5, 2021

The "LEGACY" implementation had the extra render the experimental React Concurrent Mode support fixed. But, interesting that my optimization in #749 may also be used to prevent the initial double render. Thanks, will take a look!

@lucasbordeau
Copy link

Hi, we are experiencing this bug on a complex UI involving a few dozen of atoms on many components. We've got many re-renders that slow down our web based editor, even if only in dev mode, it's not what we are expecting from a state management library.

We are currently running on the @salvoravida fork, with an alias mapping in webpack and tsconfig to keep the import ... from 'recoil';. It works ! No more re-render, thanks.

We are awaiting the new version of recoil with this fix, keep it up guys !

@drarmstr
Copy link
Contributor

drarmstr commented Jan 7, 2021

Thanks for the extra testing @lucasbordeau

@salvoravida
Copy link
Contributor

@lucasbordeau
#825

have you found a similar issue?

can you test di this pr?

facebook-github-bot pushed a commit that referenced this issue Jan 20, 2021
Summary:
Fix initial double render

issue related:

#565

#307

Issue CodeSandBox
https://codesandbox.io/s/recoil-legacy-double-render-30bjc

Fix CodeSandBox
https://codesandbox.io/s/recoil-legacy-double-render-fixed-2oxfj

Pull Request resolved: #820

Reviewed By: bezi, davidmccabe

Differential Revision: D25792710

Pulled By: drarmstr

fbshipit-source-id: 3788bb10cb88cffbd8eef40126ef566eef43e148
@realStandal
Copy link

Ran into this issue on React 17.0.1 using Recoil 0.1.3. @salvoravida's PR worked as expected, no more double rendering. I see the PR attached was merged and 0.1.3 came out after then, was Salvaravida's fix not included in it?

@drarmstr
Copy link
Contributor

The fix was merged, however it is still behind a feature flag. There is still a pending issue with React Suspense that we need a volunteer to help debug.

@JoeDuncko
Copy link

@drarmstr could you point me towards the feature flag? I may be dense, but I don't think I see it in the docs.

@drarmstr
Copy link
Contributor

drarmstr commented May 3, 2021

We don't currently have a documented feature flag mechanism, hopefully that's infrastructure we can add later. You can manually enable feature flags for the open-source nightly build on this line: https://github.com/facebookexperimental/Recoil/blob/master/src/util/Recoil_gkx.js#L14 This one is recoil_suppress_rerender_in_callback

@kentr
Copy link

kentr commented Oct 8, 2021

@drarmstr This double rendering issue is a big deal, IMO.

Is the React Suspense issue that you mentioned still a blocker? Which issue is it, and what is needed to resolve it?

@55Cancri
Copy link

55Cancri commented Oct 29, 2021

@drarmstr double rendering issue is breaking my app also. On version 0.41 and no StrictMode component at the top. I'm using in combination with react-photo-gallery library and it uses width and height to calculate and absolutely position images in the gallery grid.

The double rerendering issue breaks its calculations and the photos dont display correctly. I tried using the useRecoilState in the parent and passing down values from the recoil state to the children, but that does not fix the issue. Only if I set the recoil state into local state in a useEffect will it work properly.

Why does a component subscribing to recoil state cause it to break in this way?

@el1s7
Copy link

el1s7 commented Oct 29, 2021

@drarmstr double rendering issue is breaking my app also. On version 0.41 and no StrictMode component at the top. I'm using in combination with react-photo-gallery library and it uses width and height to calculate and absolutely position images in the gallery grid.

The double rerendering issue breaks its calculations and the photos dont display correctly. I tried using the useRecoilState in the parent and passing down values from the recoil state to the children, but that does not fix the issue. Only if I set the recoil state into local state in a useEffect will it work properly.

Why does a component subscribing to recoil state cause it to break in this way?

The issue is probably in your code, you should try using memoized values.

@55Cancri
Copy link

55Cancri commented Oct 29, 2021

@drarmstr I tried those and useMemo and useLayoutEffect did not solve the issue. The issue is more fundamental than that. If I use useState and add a console.log, it only prints once in the console and the image gallery loads correctly. If I switch to recoil, it renders twice and the app breaks.

@kentr
Copy link

kentr commented Oct 29, 2021

Even if memoized values resolve some cases, the double-rendering is a known issue that there was a PR for: #820.

The problem is that the fix is not enabled by default. It's hidden behind a feature flag.

For me, patching Recoil to enable the fix resolves the issue. It would be great if the fix were enabled by default.

@drarmstr
Copy link
Contributor

The problem is that the fix is not enabled by default. It's hidden behind a feature flag.

That fix should be enabled by default now with 0.4.1

@kentr
Copy link

kentr commented Oct 29, 2021

That fix should be enabled by default now with 0.4.1

I stand corrected!

@55Cancri
Copy link

The problem is that the fix is not enabled by default. It's hidden behind a feature flag.

That fix should be enabled by default now with 0.4.1

Really, because I'm very certain recoil is the cause of my apps issue here. I simply change to using local useState or context and suddenly the app works flawlessly, but then I switch back to recoil and the app is broken again. This sucks because the api for recoil is the best I've seen for global state management.

Also, will recoil ever become the official global state management library for React, since its made by the facebook team? Is Dan Abramov involved in the project at all? And finally, when will recoil reach version 1?

@55Cancri
Copy link

Here's a link to a code sandbox. Simply comment out the React.useState and uncomment the useRecoilState and useEffect:
https://codesandbox.io/s/react-photo-gallery-with-recoil-94bp9?file=/index.js

@drarmstr
Copy link
Contributor

drarmstr commented Nov 3, 2021

@55Cancri ,

Here's a link to a code sandbox. Simply comment out the React.useState and uncomment the useRecoilState and useEffect:
https://codesandbox.io/s/react-photo-gallery-with-recoil-94bp9?file=/index.js

Your example uses an additional useEffect() call to set the state. This means there is an initial render, then your effect changes the state causing a second render. Instead of initializing the state with useEffect() you can just set the default property when creating the atom. (The default can also be an async Promise, if you wish to use React Suspense, though it will cause a re-render when the Promise resolves.)

Also note that values stored in atoms are frozen in development mode as they should generally not be mutated. The photos implementation here seems to mutate the width property. I added a dangerouslyAllowMutability flag to workaround this.

Here's a fixed example: https://codesandbox.io/s/react-photo-gallery-with-recoil-forked-uky9u?file=/index.js

AlexGuz23 pushed a commit to AlexGuz23/Recoil that referenced this issue Nov 3, 2022
Summary:
Fix initial double render

issue related:

facebookexperimental/Recoil#565

facebookexperimental/Recoil#307

Issue CodeSandBox
https://codesandbox.io/s/recoil-legacy-double-render-30bjc

Fix CodeSandBox
https://codesandbox.io/s/recoil-legacy-double-render-fixed-2oxfj

Pull Request resolved: facebookexperimental/Recoil#820

Reviewed By: bezi, davidmccabe

Differential Revision: D25792710

Pulled By: drarmstr

fbshipit-source-id: 3788bb10cb88cffbd8eef40126ef566eef43e148
snipershooter0701 pushed a commit to snipershooter0701/Recoil that referenced this issue Mar 5, 2023
Summary:
Fix initial double render

issue related:

facebookexperimental/Recoil#565

facebookexperimental/Recoil#307

Issue CodeSandBox
https://codesandbox.io/s/recoil-legacy-double-render-30bjc

Fix CodeSandBox
https://codesandbox.io/s/recoil-legacy-double-render-fixed-2oxfj

Pull Request resolved: facebookexperimental/Recoil#820

Reviewed By: bezi, davidmccabe

Differential Revision: D25792710

Pulled By: drarmstr

fbshipit-source-id: 3788bb10cb88cffbd8eef40126ef566eef43e148
eagle2722 added a commit to eagle2722/Recoil that referenced this issue Sep 21, 2024
Summary:
Fix initial double render

issue related:

facebookexperimental/Recoil#565

facebookexperimental/Recoil#307

Issue CodeSandBox
https://codesandbox.io/s/recoil-legacy-double-render-30bjc

Fix CodeSandBox
https://codesandbox.io/s/recoil-legacy-double-render-fixed-2oxfj

Pull Request resolved: facebookexperimental/Recoil#820

Reviewed By: bezi, davidmccabe

Differential Revision: D25792710

Pulled By: drarmstr

fbshipit-source-id: 3788bb10cb88cffbd8eef40126ef566eef43e148
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests