Recoil: Warning: Cannot update a component (`xxx`) while rendering a different component (`xxx`).
A warning is occured where useRecoilValue() is used even though I write a code like one which is in the official document here.

this is my code
import React, { useEffect } from 'react';
import { atom, useRecoilState, useRecoilValue, selector } from 'recoil';
function RecoilApp() {
useEffect(() => {
console.log('test');
});
return(
<div>
Recoil App
<TextInput />
<CharCount />
</div>
);
}
const textState = atom({key: 'textState', default: ''});
function TextInput() {
const [text, setText] = useRecoilState(textState);
const onChange = event => {
setText(event.target.value);
}
return(
<div>
<input type="text" value={text} onChange={onChange} />
<br />
Echo: {text}
</div>
);
};
function CharCount() {
const count = useRecoilValue(countState);
return <>Charset Count: {count}</>;
}
const countState = selector({
key: 'countState',
get: ({get}) => {
const text = get(textState);
return text.length;
},
});
export default RecoilApp;
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 156
- Comments: 88 (10 by maintainers)
I’m working on a big refactor where dependencies will not go through React state at all. That will fix this (and make it a lot more efficient, and is needed for CM). In the meantime I don’t see a an obvious workaround unfortunately.
Thanks for reporting, I am investigating this.
You need to try with react v16.13.1. https://codesandbox.io/s/async-pine-gogdb
(edit: I’m surprised to get so many down votes. Many people probably misunderstood my comment is how to fix the warning. My apologies for not clarifying the context. It was a comment for @syunto07ka to “reproduce” the warning in codesandbox.)
The
Batcher
’s component’ssetState
is the state setter that is being called, and the main cause is becausereplaceState
fromRecoilRoot
is called when rendering subscribed components.The warning was initially added to react on the
v16.13.0
release, and highlights an anti-pattern of the react mental model.Inlining the logic in the batcher’s effect to
replaceState
solves the issue (along withsetTimeout
on thenotifyBatcherOfChange.current()
, but I don’t believe thatsetTimeout
is a reliable solution). WhileRecoilRoot
wraps a context provider, a state inside it could be a solution, but we will return to the initial problem.I understand that the main goal of the
Batcher
is to catch as manysetState
calls from subscribers as possible and delegate to react batching to gatherqueuedComponentCallbacks
and optimize the count of re-renders. Moreover, the subscribed component callback is theforceUpdate
(state setter) ofuseInterface
that is linked to subscribed components. So if many updates occur in a short duration, I prefer leaving react to handle the batching stuff rather than building a logic on top of it, and also because it is unstable.Besides, the
replaceState
will notify the batcher only with the new state reference change, and as far as I read, this is the case when a new subscription occurs.My question is, Shouldn’t we drop the batcher and leave react manage the batching of state updates ? I mean, it is like an abstraction over an abstraction, or am I mistaking something?
I think to solve the problem without dropping the
Batcher
, a work loop that schedules when to flush the subscriptions is mandatory (may have its own problems though).I found such a workaround, in child component i change parent component state with
useEffect
:I had a similar issue and it turns out the problem was how I was using it. I had an async selector which derived a value from an atom.
For example, I had a User atom and a Roles async selector. Whenever the User updated (should really only happen once) then the Roles would be loaded from the API for that User.
However, I used a hook to retrieve the User and every time the hook ran, it updated the User (in the hook), which in turn triggered a Roles API request.
Simple fix was to set the User atom from a useEffect, with the User in the deps array.
Confirming Recoil breaking hmr/fast refresh.
The error is present in both the codesandbox links
In my case, it’s because I was mutating a prop value in the child component.
BEFORE
AFTER
Hi @davidmccabe, Any ETA on this?
Inclusion of any
selector
in any FC whereby the selector callsget
on an atom, generates this error. The simplest use case in my project is:As an early adopter with high hopes for this project, I’m migrating away from Redux to Recoil!! Crossing fingers to see Recoil “stable enough” for our beta in a few months.
Thanks for your efforts on this!!
Fixed in v0.0.13 Youhouhou
I have copied and pasted your code and it works. See example in codesandbox
Fix is in the v0.0.11 release so keep watch for that.
Proposed: 15-Sep-2020 (https://github.com/facebookexperimental/Recoil/issues/534#issuecomment-691580341)
Maybe something related to hot-loader? I just had:
then I removed the react-dom alias from my webpack config
and the error changes to
Header is my component name…
Looks like for now we need to live (and can) with such warning till Recoil team will provide refactored version of
Batcher
.For now the warning is valid and based on adding new validation-warning from React team to highligh anti-pattern to use
useState
setter out of component which happens in this place.Downgrading React version to 16.12 will remove this issue if it annoying.
New warning React 16.13: https://ru.reactjs.org/blog/2020/02/26/react-v16.13.0.html#warnings-for-some-updates-during-render The details: https://github.com/facebook/react/issues/18178#issuecomment-602327720.
imho: any hacks and workaround will lead to complexity increasing and unexpected issues and it looks like a waste of time since the goal of this warning is only notify about the issue. And the fix should be centralized at least in this case.
Surprised there’s been no updates on Recoil since June. I’ve just started using it and it is almost life changing. This pescy warning is annoying and hoping it will be fixed soon?
Same here on React 17.0.2 and recoil 0.3.1.
Is it safe to ignore this warning?
I have this issue and I’m not using react hot module loading.
@davidmccabe Any idea on a rough timeline for when we can expect this refactor to be working?
same issue here. Thanks for your work.
Any update for this issue 😦 i try to add this to new project instead of redux …
No, it is not safe to ignore, it is against the model of react itself.
Your component while rendering tries to alter the state of another component, this couples both of them to each other and makes the render operation of your component non atomic and with side effects impacting other components.
Recoil uses some technique internally (for batching if my memory is good enough) that alters the state of components while rendering, and react tells us not to do this, so clearly you should not ignore the message.
AFAIK, it was related to selectors, but I remember only the initial ever code about recoil, I don’t honestly know how this became and if there is a chance to solve this issue.
If I get this warning once and everything else is working as expected, should I be concerned? Does it indicate a memory leak or something else that will affect the performance of the app?
Your provider is setting the state in the render. If you put it in a useEffect then the problem will go away 😃
It seems it’s not a problem with the library but the understanding of how it’s used in the react lifecycle.
If you had a useState for example, you wouldn’t update that directly in the render method, you’d do it inside an effect.
this worked for me. @DaniCastel any reason an arrow function had to be used? React newbie here
This happen because my component use
useRecoilValue(selector)
I found this error when:
I have the same issue when an atom has a Promise as a default value.
Yep, same issue here… it looks like the warning is only shown using selectors, pure atoms seems to be working without a warning.
Looking forward to a fix, thanks for all the hard work!
@davidmccabe - that would be great - pls post any updates when you have an ETA. Thanks again.
I was in your shoes last year. I was getting this warning, and everything else was ok. My problem was when I started coding unit tests. Them, this warning was preventing my recoil state from being updated on test environments.
So, this is still problem.
I just saw the comment from @davidmccabe talking about the re-work and subsequent fix. So that is great news! GitHub should have a way for Contributors to ‘pin’ an important comment such as that to the top, sometimes there is a lot of chaff to wade through to find the important information. I did mean updates as in a tagged version, but yes that was unfair to say with all the work on issues etc… aaand I’m adding to the chaff!
Also encountered this warning today, decided to step back to
react@16.12.0
andreact-dom@16.12.0
in the meantime. Thanks guys for your work, this library looks very promising!I have the same issue
@markerikson That was my misunderstanding too, because they said at some point about considering the use of useMutableSource as one option.
https://github.com/facebookexperimental/Recoil/issues/5#issuecomment-628796942
In Recoil, state seems React based.
+1 Having the same issue right now using React 18.0.25 & Recoil 0.7.6.
I have the same issue. It is caused by setting pageTitle (displayed in explorer tab and history) in each component after routing using recoil. Fixed after centralizing the pageTitle logic in the root of component where pageTitle is rendered and get rid of the recoil setting action.
For me it was a stupid mistake (typo). I had a memoized function, which inside of its dependencies had a Recoil setter being invoked/called, instead of just passed in the deps array.
Problematic code:
Fixed code:
Running in prod mode only hides the errors, it still happens. Have a look at my comment above and it should explain what needs to be done
Yes, #581 is still landing
@mattmogford-alcumus I completely agree that Recoil is life changing 😄 However it’s not fair to say there’s been no updates. There are quite frequent updates to master and I believe the team will eventually get to fix this issue 😄 There are several related commits already
I think replaceState shouldn’t cause Batcher update when we call getRecoilValueAsLoadable, since getRecoilValueAsLoadable just get value from RecoilNode for computing derived value. I think the following code would work, But I am not for sure. @davidmccabe