Coding 9 (Composition Patterns) Server Components - Fetching data - Directly accessing backend resources - Protecting sensitive information (like access tokens and API keys) on the server - Keeping large dependencies server-side helping in reducing client side javascript   Client Components - Adding interactivity and handling event listeners - Managing state and lifecycle effects ( useState(), useReducer(), useEffect() ) - Using browser-exclusive APIs - Custom hooks - React Class components   ## Server-only code - Its not wise to include server side code to prevent exposing logic, api keys or data also it may not work on client too - So its important to have a clear boundary - Create server side functions in different files and import `server-only` module in that file(containing server side function) which will give error at build time if its code is used in client components ```text src/app utils server-utils.jsx server-route page.jsx client-route page.jsx ``` In `src/app/utils/server-utils.jsx` ```js import "server-only"; export const ServerSideFunction = () => { console.log( `use multiple libraries, use environment variables, interact with a database, process confidential information` ); return "server result"; }; ``` In `src/app/server-route/page.jsx` ```js import { ServerSideFunction } from "../utils/server-utils"; export default function ServerRoutePage() { console.log("Server router rendered"); const result = ServerSideFunction(); return ( <>

ServerRoutePage

{result}

); } ``` In `src/app/client-route/page.jsx` ```js "use client"; import { ServerSideFunction } from "../utils/server-utils"; export default function ClientRoutePage() { console.log("Client route rendered"); const result = ServerSideFunction(); return ( <>

ClientRoutePage

{result}

); } ```   **Third Party Packages** - third party packages in npm dont use 'use client' directive so they cant be used in server components so we need to encapsulate them in another client component and use it instead - It is possible to use nested client side component inside server side component Example : Using `react-slick` package Structure ```text src/app components ImageSlider.jsx ImageSlider.css utils server-utils.jsx server-route page.jsx client-route page.jsx ``` In `src/app/components/ImageSlider.jsx` ```js "use client"; // import { ServerSideFunction } from "../utils/server-utils"; import Slider from "react-slick"; // Import css files import "slick-carousel/slick/slick.css"; import "slick-carousel/slick/slick-theme.css"; import "./ImageSlider.css"; export default function ImageSlider() { console.log("Client route rendered"); // const result = ServerSideFunction(); var settings = { dots: true, infinite: true, speed: 500, slidesToShow: 1, slidesToScroll: 1, }; return ( // <> //

ClientRoutePage

//

{result}

// //
picsum
picsum
picsum
picsum
picsum
{/* picsum */}

6

); } ``` In `src/app/components/ImageSlider.css` ```css .fit-con { display: flex !important; justify-content: center; } ``` In `src/app/server-route/page.jsx` ```js import ImageSlider from "../components/ImageSlider"; import { ServerSideFunction } from "../utils/server-utils"; export default function ServerRoutePage() { console.log("Server router rendered"); const result = ServerSideFunction(); return ( <>

ServerRoutePage

{result}

); } ``` **Context Providers** - Context providers are typically rendered near the root of an application to share global application state and logic. Eg : App theme - React context is not supported in Server Compinent so just like encapusalating third package in separate client component we need to do same for this Structure ```text src/app layout.jsx client-route page.jsx components theme-provider.jsx ``` In `src/app/components/theme-provider.jsx` ```js "use client"; import { createContext, useContext } from "react"; const defaultTheme = { colors: { primary: "#007bff", secondary: "#6c757d", }, }; const ThemeContext = createContext(defaultTheme); export const ThemeProvider = ({ children }) => { return ( {children} ); }; export const useTheme = () => useContext(ThemeContext); export { ThemeContext }; ``` In `src/app/layout.jsx` ```js import { Inter } from "next/font/google"; import { ThemeProvider } from "./components/theme-provider"; export const metadata = { title: "Create Next App", description: "Generated by create next app", }; export default function RootLayout({ children }) { return ( {children} ); } ``` In `src/app/client-route/page.jsx` ```js "use client"; import { useContext } from "react"; import { ThemeContext } from "../components/theme-provider"; export default function ClientRoutePage() { const theme = useContext(ThemeContext); return (

Client Route

); } ``` To update the context value, use useState and transfer state, stateChanger t value of context provider ```js import ReactDOM from "react-dom"; import React, { useState } from "react"; import authContext from "./authContext"; import Login from "./Login"; const App = () => { const [authenticated, setAuthenticated] = useState(false); return (
user is {`${authenticated ? "" : "not"} authenticated`}
); }; ReactDOM.render(, document.getElementById("container")); ```   ## Client-only Code - To prevent unintended server side usage of client code we can install and import package `client-only`   Client Component Placement - It is recommended to position client components lower in the component tree - Once the component is client component all the child component becomes client components too ```text src/app components navbar.jsx navlink.jsx navsearch.jsx landing-page page.jsx ``` In components ```js // navlink.jsx export default function Navlink() { console.log("Navlink loaded"); return
NavLink
; } //navsearch.jsx "use client"; import { useState } from "react"; export default function NavSearch() { const [search, setSearch] = useState(""); console.log("NavSearch loaded2"); return
NavSearch
; } //navbar.jsx import Navlink from "./navlink"; import NavSearch from "./navsearch"; export default function NavBar() { console.log("navbar loaded"); return ( <>
NavBar
); } ``` - useState hook can be used in navbar too but since its usage is required only in navsearch file so its best to use it there otherwise navbar needs to be a client component and navlink will be client component too In `src/app/landing-page.jsx` ```js import NavBar from "../components/navbar"; export default function LandingPage() { return (

Landing Page

); } ```   **Interleaving Server and Client components** - Server component cannot be directly used inside client component as they are automatically converted to client component by default - So a workaround is needed for this ie passing server component as prop to client component ```text src/app interleaving page.jsx components client-component.jsx server-component.jsx ``` In `src/app/server-component.jsx` ```js import fs from "fs"; export default function ServerComponent() { console.log("ServerComponent loaded"); const fileBuffer = fs.readFileSync("package.json"); return (

Server Component

); } ``` Following wont work and will give error that fs is not working as server component which is children of client component becomes client component In `src/app/interleaving.jsx` ```js import ClientComponent from "../components/client-component"; export default function InterleavingPage() { console.log("InterleavingPage loaded"); return (
); } ``` In `src/app/client-component.jsx` ```js "use client"; import { useState } from "react"; import ServerComponent from "./server-component"; export default function ClientComponent() { console.log("client component loaded"); const [state, seyState] = useState(); return (

Client Component

); } ``` Passing server component as props instead In `src/app/interleaving.jsx` ```js import ClientComponent from "../components/client-component"; import ServerComponent from "../components/server-component"; export default function InterleavingPage() { console.log("InterleavingPage loaded"); return (
); } ``` In `src/app/client-component.jsx` ```js "use client"; import { useState } from "react"; // import ServerComponent from "./server-component"; export default function ClientComponent({ children }) { console.log("client component loaded"); const [state, seyState] = useState(); return (

Client Component

{children} {/* */}
); } ```