In my opinion one of the most difficult things about nextjs 13 (app router) is figuring out when to utilize the vast number of different features offered (Am I alone here?). There's not a ton of information yet about best practices in real world scenarios so I'm wondering if there is a silent consensus out there about how to do things that I just haven't stumbled upon. I'll provide an example of some basic web functionality that I have struggled to create with nextJs due to my ignorance of the standard nextjs way of doing things.
First, heres a list of features that I struggle to utilize due to uncertainty about best practices.
Server/client component patterns
- Keep client components at the leaves of your tree (then there is no way to have your server components know about the state of your client components without having them manipulate the url or using a global state manager)
- Nest server components inside your client components (you cannot pass props to the children so your server components still can't know about the clients state)(
- Using query params in your server components as a channel of communication from client components (you can only access query params in page.tsx files so you have to do tons of prop drilling for this to work which I understand is not advised when using server components)
Getting data:
- Load and display it in a server component using plain typescript/javascript
- Load it in a server component and display it in a client component by passing serialized data through props (maybe because you need to be able to click on the items)
- Fetch the data in a client component using server actions
- Fetch the data in a client component using "fetch"
- Use a state management system like redux and handle data fetching through the store
Submitting data:
- using server actions in a client component
- using "fetch" to submit the form
To be clear, I'm pretty sure I understand how to implement any one of these strategies in a vacuum but have no intuition for the way an application of any reasonable size would chose to utilize these different features.
Heres an example of web functionality that is trivial to implement using the good old create-react-app structure but I find myself confused and uncertain when trying to use nextjs 13.
Desired functionality
I have a layout with an auto complete search component and children like this.
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div className="flex flex-col">
<div className="prose">
<h1>Algorithm</h1>
<AlgorithmSearch />
<div>{children}</div>
</div>
</div>
);
}
The AlgorithmSearch component shown here will render a SearchField client component that will modify the search params in the url. There will also be an OptionsDisplay server component rendered inside the AlgorithmSearch component. This server component will query the database based on the searchParams set by the SearchField component and display them as options. When an option is selected the url will change and display a new page in the {children} area in the layout above.
Unfortunately the strategy above does not work because server components and the layouts do not have access to searchParams. It would seem that my OptionsDisplay component must be a client component and make use of the useSearchParams() hook, then I could load the options with fetch. This directly contradicts the strategy of leaving data loading to the server components.
Where did I go wrong here and how is this kind of thing usually done with nextjs 13?