Next.js Discord

Discord Forum

Cannot update a component while rendering a different component

Unanswered
Turkish Angora posted this in #help-forum
Open in Discord
Avatar
Turkish AngoraOP
I think I am not understanding the interaction between client and server components, since the following client component yields an error:

Cannot update a component (Router) while rendering a different component (default). To locate the bad setState() call inside default, 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

Avatar
you cannot use a server component inside a client component.
Avatar
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
Avatar
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?
Avatar
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?
Avatar
client components can rerender, server components cannot. so you cannot have server components inside client components.

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
Avatar
Turkish AngoraOP
Blimey
Avatar
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?
Avatar
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
Avatar
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 component
Avatar
I 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
Avatar
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
Avatar
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
Avatar
Asian black bear
It has to be a server component. You can wrap 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>
Avatar
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…?
Avatar
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
Avatar
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 🙏