- ✔️ TypeScript
- ✔️ .map
- ✔️ JSX
- ✔️ FC
- ✔️ interfaces
- ✔️ props
- ✔️ setTimeout
- ✔️ setInterval
- ✔️ useState
- ✔️ useEffect
- ✔️ useRef
- ✔️ useMemo (when value passed in child props)
- ✔️ useCallback (when fn passed in child props)
- ✔️ useContext
- ✔️ useReducer
- ✔️ fetch (browser Vs. server)
- ✔️ Suspense
- ✔️ Atoms
- ✔️ TailwindCSS
- ✔️ Custom Hooks (useFetch, useCounter)
- ✔️ Static front-end routes
- ✔️ Dynamic front-end routes
- ✔️ Server actions
- ✔️ API
- ✔️ Controller
- ✔️ Services
- ✔️ Error Handling
- ✔️ axios ( ... ) Vs. fetch ( ... )
- ✔️ .env & .env.d.ts (data types)
- ✔️ Middleware
- ✔️ Jose JWT
JS bundle on the front-end is not needed in server components but needed in client components for interactivity
Based on the URL structure, i.e., if the URL has a dynamic ID in it, for example, it is a dynamic route - no matter whether for a component or an API endpoint
Based on:
A) If dynamic functions like ( cookies( .... ) ) are encountered. If yes, then dynamic SSR is perfomred - no matter a component or an API endpoint
B) If caching is done or not. If yes, then for components always static rendering will take place (with or without re-validation)
On-demand Vs. Interval-based
We have basically two options: inside server component Vs. via API Endpoint. There is a third one too: inside client components, but this one should be avoided as much as possible in the favour of fetching in the server components.
Anyways, evaluate these two options based on the following:
A) Based on the simplicity of the request. If simple, then RSC-based search is better
B) Based on if re-usability of the fetched data in multiple components is required. If yes, then API endpoint-based search is better.
Caching can take place at two different levels in any app: at the app level or at the platform level. In React.js, using React.cache ( .... ) performs caching from a server component at the app level within a component on the front-end in the memory for as long as the component doesn't unmount, because When using React.cache ( .... ), the cache is tied to the component's lifecycle.
Whereas using the { cache: "force-cache" } flag in a fetch ( .... ) request makes the browser cache the data on the front-end in the storage (mostly, but can also store in the memory) for some time.
Accessing the app-level cache is faster than the platform-level cache. We can use both in React.js at the same time to ensure that we quickly access the data from the component when we want to but also have a back-up of it in the browser's cache, so that data access is possible after un-mounting and re-mounting the component in the DOM.
In short, if we use React.cache ( .... ), de-duplication of fetch requests happens at the component level for that network request, but when we use { cache: "force-cache" }, then de-duplication of that fetch request happens at the app level (even if the same request is being sent out to the same endpoint from multiple componentts, that data will be available from the browser).
But in Next.js ....
Next.js automatically handles deduplication of fetch requests during rendering, which simplifies data fetching and improves performance without needing to manually use React's caching features. This means you can focus on building your application without worrying about redundant network requests. All we need to do is use the { cache: "force-cache" } in fetch requests; this makes the route get statically rendered too (data is fetched during build time). So, in Next.js, we don't have to use React.cache ( .... ) API directly.
- If we use { cache: "force-cache" } in Next.js, the route will get statically rendered
- If we use { cache: "no-cache" }, the route will get dynamically rendered (SSR) for that request (not the whole page!).
- If we use { next: { revalidate: 3600 }}, the route will get statically rendered but also incrementally rendered (ISR) automatically.
From the docs ....
"For example, if you need to use the same data across a route (e.g. in a Layout, Page, and multiple components), you do not have to fetch data at the top of the tree, and forward props between components. Instead, you can fetch data in the components that need it without worrying about the performance implications of making multiple requests across the network for the same data."
Lazy loads a component, including its images, its JS bundle, etc. In Next.js, however, we don't use lazy ( ... ), rather we use the dynamic ( .... ) function of Next.js itself. Next.js has implemented its lazy loading under the hood a bit differently than React.js.
- SSR: Next.js provides built-in support for server-side rendering (SSR), which means that the lazy-loaded components are rendered on the server before being sent to the client. React.lazy() does not provide SSR out of the box.
- Automatic Code Splitting: Next.js automatically splits the code into smaller chunks, which are then lazy-loaded. React.lazy() requires you to manually handle code splitting using Webpack or another bundler.
- Fallback Component: Next.js provides a built-in fallback component (e.g., a loading indicator) that is rendered while the lazy-loaded component is being loaded. React.lazy() requires you to manually provide a fallback component using Suspense.