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;
I have copied and pasted your code and it works. See example in codesandbox
Thanks, ecreeth.
As you say that, my code works, but warning is occured in my browser.
Humm, I wonder that the codesandbox occured no warning at console like the image.
You need to try with react v16.13.1.
https://codesandbox.io/s/async-pine-gogdb

The error is present in both the codesandbox links
it's my installed dependences in pakcage.json.
so yeah, "16.13.1" is correct.
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "3.4.1",
"recoil": "0.0.7"
},
Thanks for reporting, I am investigating this.
Maybe something related to hot-loader?
I just had:
Warning: Cannot update a component from inside the function body of a different component.
then I removed the react-dom alias from my webpack config
alias: {
'react-dom': '@hot-loader/react-dom',
},
and the error changes to
Warning: Cannot update a component (`Batcher`) while rendering a different component (`Header`). To locate the bad setState() call inside `Header`, follow the stack trace as described in https://fb.me/setstate-in-render
Header is my component name...
Maybe something related to hot-loader?
I just had:Warning: Cannot update a component from inside the function body of a different component.then I removed the react-dom alias from my webpack config
alias: { 'react-dom': '@hot-loader/react-dom', },and the error changes to
Warning: Cannot update a component (`Batcher`) while rendering a different component (`Header`). To locate the bad setState() call inside `Header`, follow the stack trace as described in https://fb.me/setstate-in-renderHeader is my component name...
I noticed also that setters stop working when hot reloading is set ... so having this related as well sounds like something worth exploring
Yes, we have a known issue with hot module loading at the moment.
Having the same issue. Thanks for reporting @syunto07ka and thanks for investigating @davidmccabe.
I have this issue and I'm not using react hot module loading.
The Batcher's component's setState is the state setter that is being called, and the main cause is because replaceState from RecoilRoot 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 with setTimeout on the notifyBatcherOfChange.current(), but I don't believe that setTimeout is a reliable solution). While RecoilRoot 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 many setState calls from subscribers as possible and delegate to react batching to gather queuedComponentCallbacks and optimize the count of re-renders.
Moreover, the subscribed component callback is the forceUpdate (state setter) of useInterface 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).
What if Batcher itself was rendered whenever a selector was rendered. eg, treat it as if it depends on all selectors. Then it would automatically queue its useEffect, and you would not need notify the Batcher of a change in replaceState, Batcher could test for the change when running it's useEffect. I think this also solves the "double render" whenever a selector changes dependencies.
I see now that replaceState is called under other conditions that are not part of a render.
This particular issue occurs because:
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.
@davidmccabe - that would be great - pls post any updates when you have an ETA. Thanks again.
I am getting the same error, In my case this error pops up if I use the selector variable as a dependency in my component's useEffect
For eg:
in recoil:
// get decoded URL of meetingId
export const getDecodedMeetingId = selector ({
key: 'decodedMeetingIdState',
get: ({get}: any) => {
const meetingId = get(meetingIdState);
return decodeURI(meetingId);
}
});
And then my component useEffect
const meetingStatus = useRecoilValue(getDecodedMeetingId);
// side-effects
useEffect(()=>{
if (meetingStatus) {
console.log('Begin Timer');
startTimer();
} else {
setTimer(prev => prev);
}
},[meetingStatus]);
Hopefully this helps. If I am doing something wrong, please let me know.
@davidmccabe I'm very curious - can you give any technical details on what you're doing and how it will improve CM compat? My general understanding was that _any_ non-React-based state management approach will have issues with CM, because it can't tie in to React's ability to reorder state updates based on render priorities.
@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.
Hi,
any ETA on this fix ? https://github.com/facebookexperimental/Recoil/issues/12#issuecomment-631201906
This is the problem, I am facing when using recoil...
https://github.com/facebookexperimental/Recoil/issues/12#issuecomment-631238293
Confirming Recoil breaking hmr/fast refresh.
Hi, i found this comment from react-final-form where they had a similar issue and solved it:
https://github.com/final-form/react-final-form/issues/751#issuecomment-606212893
Hope this helps
I have the same issue
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
javascript
const replaceState = (replacer, shouldNotNotifyBatcher) => {
\\ other code
if (shouldNotifyBatcher === true) return;
nullthrows(notifyBatcherOfChange.current)();
};
javascript
function getRecoilValueAsLoadable<T>(
store: Store,
{key}: AbstractRecoilValue<T>,
): Loadable<T> {
let result: Loadable<T>;
// Save any state changes during read, such as validating atoms,
// updated selector subscriptions/dependencies, &c.
Tracing.trace('get RecoilValue', key, () =>
store.replaceState(
Tracing.wrap(state => {
const [newState, loadable] = getNodeLoadable(store, state, key);
result = loadable;
return newState;
}),
true
),
);
return (result: any); // flowlint-line unclear-type:off
}
Same issue.
Hi @davidmccabe, Any ETA on this?
Inclusion of any selector in any FC whereby the selector calls get on an atom, generates this error. The simplest use case in my project is:
//
// foobarState.ts
//
export const foo = atom<boolean>({ key: "foo", default: true });
export const bar = selector<boolean>({ key: "bar", get: ({ get }) => !get(foo) });
//
// component.tsx
//
...
export default ((props) => {
const foobar = useRecoilValue(bar);
return <>Hello World</>
}
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!!
I got his warning because I used a selector get another async selector get. Some example code
export const asyncSelector = selector>({
key: 'AsyncSelector ',
get: async ({ get }) => {
const response = await fakeData();
const data = await response.json();
await new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 200);
});
return data
},
});
export const getAsyncSelector= selectorFamily({
key: 'GetAsyncSelector',
get: (params) => ({ get }) => {
return get(asyncSelector ).slice(params);
},
});
Also encountered this warning today, decided to step back to [email protected] and [email protected] in the meantime. Thanks guys for your work, this library looks very promising!
Any update for this issue :( i try to add this to new project instead of redux ...
// store.js
export const todoListTypeState = atom({
key: "todoListTypeState",
default: "snack",
});
export const todoListState = atom({
key: "todoListState",
default: [
{ type: "snack", content: "cake" },
{ type: "drink", content: "water" },
],
});
export const todoListSelector = selector({
key: "todoListSelector",
get: ({ get }) => {
const type = get(todoListTypeState);
const todoList = get(todoListState);
return todoList.filter((item) => item.type === type);
},
set: ({ set }, newValue) => {
set(todoListState, newValue);
},
});
// Todo.js
const todoList = useRecoilValue(todoListState); // :} good
const [typedTodoList, setTodoList] = useRecoilState(todoListSelector); // :{ warning
waitting...
same issue here. Thanks for your work.
I found such a workaround, in child component i change parent component state with useEffect:
function Child () {
const [ref, dimensions] = useDimensions()
const {setDimensions} = useContext(ParentContext)
// bad
setDimensions(dimensions)
// good
useEffect(() => {
setDimensions(dimensions)
})
return <div ref={ref}></div>
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.
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!
I have the same issue when an atom has a Promise as a default value.
Should we track the HMR issue separately? For us that is the bigger blocker. Specifically, we see all state stop updating after any HMR.
@natew - there is #247 for HMR
@drarmstr look like https://github.com/facebookexperimental/Recoil/pull/463 should fix this?
I found this error when:
do we have a fix for this? I am facing a similar error. Using recoil selector for an async call.
Also this commit and #399 help. These should limit to situations we see the warning, but it can still show up and we need to resolve that with React.
I have copied and pasted your code and it works. See example in codesandbox
did you tried in CRA or custome react App?
Hi any fix on this issue?
Update: was using the example on the recoiljs website, changing it to SSR and works without problems, except a typescript error that isn't related to this issue.
In NextJS i'm seeing the error Cannot update a component (Batcher) while rendering a different component (xxx) only in development e.g. HMR - haven't seen it yet on after built.
@nikolasveneti because production build does not log warnings
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?
@mattmogford-alcumus I completely agree that Recoil is life changing :D 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 :D There are several related commits already
@mattmogford-alcumus I completely agree that Recoil is life changing :D 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 :D There are several related commits already
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!
This also happened for me in a case in which a component was rerendering too fast.
This happen because my component use useRecoilValue(selector)
Any update for this issue
Any update for this issue
unfortunately not yet ! so live with the warning without any hacking around ( should not ) ! the error must be fixed in the core of the lib not working around , so until then just ignore the warning, at least it works and nothing crashes (hopefully), i still use it in my beta project. I forgot to mention that i use snowpack and so annoyed that the package has not supported ES module, hope the author fix it soon in late of this month because Recoil is really cool !
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)
I'm seeing this in 0.0.11 still. Here's a sample set of tests that are throwing it:
describe("Container", () => {
it("renders expected markup", () => {
const { container } = mount();
expect(container).toMatchSnapshot();
});
it("does not have accessibility violations", async () => {
const { container } = mount();
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});
Fixed in v0.0.13
Youhouhou
v0.0.13 works for me!
Excellent!!
confirmed : all fixed : the warning; useRecoilState bug with writable atom ( selector ) ; ESM support, web_modules compatible for snowpack. Thank you !
Can I see example of a test that's working for someone? I'm now on 0.0.13 and seeing the Batcher warning on this:
describe("IrrigationEditTable", () => {
it("renders correctly", () => {
let wrapper;
act(() => {
wrapper = renderedComponent();
});
expect(wrapper).toMatchSnapshot();
});
});
I am Also Facing the same warning in my console
@drarmstr @davidmccabe I can see that 0.13 is published on npm, but it's not listed under releases page here, can we see a change log?
this helped me to solve my issue.
I had a callback inside a memoed component but it wasn't using useEffect
@drarmstr @davidmccabe I can see that 0.13 is published on npm, but it's not listed under releases page here, can we see a change log?
Yes, #581 is still landing
I found this error when:
- I had a setState in parent component (e.g const [state, _setState_] = useState({}))
- I passed this setState to a child component and used it in a onClick={setState("value")}
- I solved this problem adding the arrow function in the onClick call
this worked for me. @DaniCastel any reason an arrow function had to be used? React newbie here
In my case, it's because I was mutating a prop value in the child component.
BEFORE
import React from 'react';
const Todo = ({ text, todo, todos, setTodos }) => {
const deleteHandler = () => {
setTodos(todos.filter(el => el.id !== todo.id)) // mutauing a prop here
}
return (
<div className="todo">
<li className="todo-item">{text}</li>
<button className="complete-btn"><i className="fas fa-check"></i></button>
<button className="trash-btn" onClick={deleteHandler()}><i className="fas fa-trash"></i></button>
</div>
);
}
export default Todo;
AFTER
import React from 'react';
const Todo = ({ text, todo, todos, setTodos }) => {
const todosCopy = JSON.parse(JSON.stringify(todos));
const deleteHandler = () => {
setTodos(todosCopy.filter(el => el.id !== todo.id)) // mutating a copy of prop value here
}
return (
<div className="todo">
<li className="todo-item">{text}</li>
<button className="complete-btn"><i className="fas fa-check"></i></button>
<button className="trash-btn" onClick={deleteHandler}><i className="fas fa-trash"></i></button>
</div>
);
}
export default Todo;
@pranavkumar389 Array.prototype.filter doesn't mutate its original array.
Any updates at this issue?
I'm facing it in my custom IntlProvider. In a nutshell, I'm wrapping it (from react-intl) in a custom component that stores the selected locale in my Recoil state for further usage by my own selectors.
Here is a sample code:
import React, { ReactElement } from 'react'
import { IntlProvider } from 'react-intl'
import { OptionalIntlConfig } from 'react-intl/src/components/provider'
import { useSetRecoilState } from 'recoil'
import { locale as localeAtom } from 'state/recoil/intl/locale'
export interface RecoilIntlProviderProps extends OptionalIntlConfig {
children: ReactElement
}
const RecoilIntlProvider = (props: RecoilIntlProviderProps): ReactElement => {
const setRecoilIntl = useSetRecoilState(localeAtom)
setRecoilIntl(props.locale)
return <IntlProvider {...props} />
}
export default RecoilIntlProvider
And my atom:
import { atom } from 'recoil'
import { PREFIX } from './constants'
const KEY = `${PREFIX}::LOCALE`
export const locale = atom<string>({
key: KEY,
default: '',
})
To make it work, you need to use the following tree in your app.js(ts):
<RecoilRoot>
<RecoilIntlProvider locale={locale ?? 'pt-BR'} messages={messages}>
<Component {...pageProps} />
</RecoilIntlProvider>
</RecoilRoot>
And my warning in the console log:
Warning: Cannot update a component (`Batcher`) while rendering a different component (`RecoilIntlProvider`). To locate the bad setState() call inside `RecoilIntlProvider`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
RecoilIntlProvider@webpack-internal:///./components/Base/RecoilIntlProvider/recoil-intl-provider.tsx:23:87
RecoilRoot@webpack-internal:///../.yarn/$$virtual/recoil-virtual-0c2fe5134c/0/cache/recoil-npm-0.1.2-9a0edbd2b9-c69105dd7d.zip/node_modules/recoil/es/recoil.js:1722:1
BudApp@webpack-internal:///./pages/_app.tsx:70:19
ErrorBoundary@webpack-internal:///../.yarn/$$virtual/@next-react-dev-overlay-virtual-ba69454c0b/0/cache/@next-react-dev-overlay-npm-10.0.0-5db65d7be6-f38cbe7f69.zip/node_modules/@next/react-dev-overlay/lib/internal/ErrorBoundary.js:23:47
ReactDevOverlay@webpack-internal:///../.yarn/$$virtual/@next-react-dev-overlay-virtual-ba69454c0b/0/cache/@next-react-dev-overlay-npm-10.0.0-5db65d7be6-f38cbe7f69.zip/node_modules/@next/react-dev-overlay/lib/internal/ReactDevOverlay.js:73:20
Container@webpack-internal:///../.yarn/$$virtual/next-virtual-6f4174843d/0/cache/next-npm-10.0.0-82dc2f1372-c01b177cb2.zip/node_modules/next/dist/client/index.js:173:20
AppContainer@webpack-internal:///../.yarn/$$virtual/next-virtual-6f4174843d/0/cache/next-npm-10.0.0-82dc2f1372-c01b177cb2.zip/node_modules/next/dist/client/index.js:641:18
Root@webpack-internal:///../.yarn/$$virtual/next-virtual-6f4174843d/0/cache/next-npm-10.0.0-82dc2f1372-c01b177cb2.zip/node_modules/next/dist/client/index.js:757:18
Looking forward for a fix in this issue :)
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.
I had a similar issue just now and solved it the very same way @nickhow83 did. So in my case:
Any updates at this issue?
I'm facing it in my custom
IntlProvider. In a nutshell, I'm wrapping it (fromreact-intl) in a custom component that stores the selected locale in my Recoil state for further usage by my own selectors.Here is a sample code:
import React, { ReactElement } from 'react' import { IntlProvider } from 'react-intl' import { OptionalIntlConfig } from 'react-intl/src/components/provider' import { useSetRecoilState } from 'recoil' import { locale as localeAtom } from 'state/recoil/intl/locale' export interface RecoilIntlProviderProps extends OptionalIntlConfig { children: ReactElement } const RecoilIntlProvider = (props: RecoilIntlProviderProps): ReactElement => { const setRecoilIntl = useSetRecoilState(localeAtom) setRecoilIntl(props.locale) return <IntlProvider {...props} /> } export default RecoilIntlProviderAnd my atom:
import { atom } from 'recoil' import { PREFIX } from './constants' const KEY = `${PREFIX}::LOCALE` export const locale = atom<string>({ key: KEY, default: '', })To make it work, you need to use the following tree in your
app.js(ts):<RecoilRoot> <RecoilIntlProvider locale={locale ?? 'pt-BR'} messages={messages}> <Component {...pageProps} /> </RecoilIntlProvider> </RecoilRoot>And my warning in the console log:
Warning: Cannot update a component (`Batcher`) while rendering a different component (`RecoilIntlProvider`). To locate the bad setState() call inside `RecoilIntlProvider`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render RecoilIntlProvider@webpack-internal:///./components/Base/RecoilIntlProvider/recoil-intl-provider.tsx:23:87 RecoilRoot@webpack-internal:///../.yarn/$$virtual/recoil-virtual-0c2fe5134c/0/cache/recoil-npm-0.1.2-9a0edbd2b9-c69105dd7d.zip/node_modules/recoil/es/recoil.js:1722:1 BudApp@webpack-internal:///./pages/_app.tsx:70:19 ErrorBoundary@webpack-internal:///../.yarn/$$virtual/@next-react-dev-overlay-virtual-ba69454c0b/0/cache/@next-react-dev-overlay-npm-10.0.0-5db65d7be6-f38cbe7f69.zip/node_modules/@next/react-dev-overlay/lib/internal/ErrorBoundary.js:23:47 ReactDevOverlay@webpack-internal:///../.yarn/$$virtual/@next-react-dev-overlay-virtual-ba69454c0b/0/cache/@next-react-dev-overlay-npm-10.0.0-5db65d7be6-f38cbe7f69.zip/node_modules/@next/react-dev-overlay/lib/internal/ReactDevOverlay.js:73:20 Container@webpack-internal:///../.yarn/$$virtual/next-virtual-6f4174843d/0/cache/next-npm-10.0.0-82dc2f1372-c01b177cb2.zip/node_modules/next/dist/client/index.js:173:20 AppContainer@webpack-internal:///../.yarn/$$virtual/next-virtual-6f4174843d/0/cache/next-npm-10.0.0-82dc2f1372-c01b177cb2.zip/node_modules/next/dist/client/index.js:641:18 Root@webpack-internal:///../.yarn/$$virtual/next-virtual-6f4174843d/0/cache/next-npm-10.0.0-82dc2f1372-c01b177cb2.zip/node_modules/next/dist/client/index.js:757:18Looking forward for a fix in this issue :)
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.
@syunto07ka I have the same problem, but when I run the "npm run prod" code, this error disappears. I only see this error in development mode.
@syunto07ka I have the same problem, but when I run the "npm run prod" code, this error disappears. I only see this error in development mode.
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
Most helpful comment
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.