Cannot update a component while rendering a different component
Unanswered
Turkish Angora posted this in #help-forum
Turkish AngoraOP
I think I am not understanding the interaction between client and server components, since the following client component yields an error:
The error indicated on the
My
If I remove the server component, no error.
If I remove the call to
For the life of me I cannot see where I am updating the state at the wrong time, during a render. This seems like perfectly legitimate react code to me, and so I believe there is something about the server component interaction.
No amount of AI has been able to help me 🤣
Can any of you humans?
Cannot update a component (Router
) while rendering a different component (default
). To locate the bad setState() call insidedefault
, follow the stack trace as described in https://react.dev/link/setstate-in-render
The error indicated on the
useSearchParams()
, but I believe it really just points at the beginning of the component.My
<SearchResults />
is server component which literally just spits out static HTML right now, doing nothing else, just while debugging.If I remove the server component, no error.
If I remove the call to
setQuery()
, no error.For the life of me I cannot see where I am updating the state at the wrong time, during a render. This seems like perfectly legitimate react code to me, and so I believe there is something about the server component interaction.
No amount of AI has been able to help me 🤣
Can any of you humans?
const Page = () => {
const searchParams = useSearchParams();
const router = useRouter();
const [inputValue, setInputValue] = useState('');
const [query, setQuery] = useState('');
// Initialize state based on query parameter
useEffect(() => {
const initialQuery = searchParams.get('q') || '';
if (initialQuery !== query) {
setInputValue(initialQuery);
setQuery(initialQuery);
}
}, [searchParams]);
const handleOnChange = (e: ChangeEvent<HTMLInputElement>) => {
};
const handleSearch = (e: FormEvent<HTMLFormElement>) => {
};
return (
<Centred className="flex flex-col gutterless:pt-12 transition-all">
<div className="flex flex-col transition-all">
<Card className="card w-full overflow-hidden gutterless:rad-shadow3 max-gutterless:py-6 gutterless:mb-6 transition-all">
<CardHeader className="text-[var(--text1)]">
<CardTitle className="text-search">Search Kadampa teachings</CardTitle>
</CardHeader>
<CardContent className="text-[var(--text1)] w-full">
<SearchForm onSubmit={handleSearch} value={inputValue} onChange={handleOnChange} />
</CardContent>
</Card>
{query && (
<Suspense fallback={<Busy />}>
<SearchResults query={query} />
</Suspense>
)}
</div>
</Centred>
);
};
30 Replies
you cannot use a server component inside a client component.
Turkish AngoraOP
Hmm. The docs say you can. The example app that I built during the tutorial does so.
It renders fine, but the console has this error in it, which is disconcerting
The example app that I built during the tutorial does so.could you show how you use a server component in a client component in this case?
Turkish AngoraOP
Just looking, I think you may be right. I don't know why I thought that. Perhaps because the pages are server components.
That is a deal-breaker, almost the whole point for me. I don't know enough about the architecture, but I would have imagined they could have somehow allowed server components to be rendered by client components.
So a server component can't really take props from the state of a client component?
client components can rerender, server components cannot. so you cannot have server components inside client components.
but your client component can have a
but your client component can have a
children
prop, then you can do this, just fine:<ClientComponent>
<ServerComponent />
</ClientComponent>
yes. server components cannot simply take props, states or any runtime values from client components
but you can do this: https://nextjs-faq.com/sharing-client-side-state-with-server-components
Turkish AngoraOP
Blimey
Asian black bear
Or, the server component will become a client component, just without you realizing it / marking it with "use client". But the error here seems to have something to do with react states. I'm not sure what the
<Suspense>
is doing here within a client component?Turkish AngoraOP
Because <SearchResults /> is an awaitable server component. As I say, this is all working, just some messages in the console.
But I will change to the pattern, thanks @joulev
Asian black bear
Ah yes if that's
async
then it wouldn't work.I would suggest taking the
searchParams
from the Page Props, not via useSearchParams
, and move all the setInputValue
logic to the actual SearchForm
component, which is then a client component. That way, this Page
component stays server, and you can await your Results componentI just checked your code and it seems this one here is exactly what you should be doing. Same thing – storing search query and search for things server side
Turkish AngoraOP
Hmm, actually not seeing how that works. Where am I putting the SearchResults component? I cannot have it within a client component at all, even with no props?
It has to be a page?
I believe you alluded to this @joulev
Going to experiment with that pattern
Yes… but also what Kevin said above is correct. Only the form should be a client component, the search result and the entire page should remain a server component
Asian black bear
It has to be a server component. You can wrap
The simplest path here is to move literally all the states or handlers to your form component (client component).
Then get the query from the Page props.
So your paradigm looks like this, simplistically
SearchResults
with client components if you want, but you have to have it defined on a server component.The simplest path here is to move literally all the states or handlers to your form component (client component).
Then get the query from the Page props.
So your paradigm looks like this, simplistically
<Page> // server. Take the `searchParams.q` from the page props
<SearchForm /> // client, include all routing / input state logic
<Suspense>
<SearchResults query={query} /> // server, async
</Suspense>
</Page>
Turkish AngoraOP
Yes, I understood that. Thanks also @Asian black bear
Ok, I’ll give that a go. Presently installing new lights.
Although now the prop has re-appeared on the search results…?
query here is from searchParams.q and not from a react state
The react state is inside <SearchForm /> which stays there and cannot get to <SearchResults />. The prop here is from searchParams data directly available to the page server component
Turkish AngoraOP
Righto. Need to rework the architecture I had in my brain, got totally the wrong end of the stick with this. Thanks both 🙏