Next.js Discord

Discord Forum

Nextjs for landing page with both ssr and some csr

Answered
Harlequin posted this in #help-forum
Open in Discord
HarlequinOP
Trying to use nextjs for building my landing page but facing issues with using both ssr and csr in same component.
I have a component navbar

import { useEffect, useState } from "react";
import navbar_logo from "../../assets/Vector.svg";
import styles from "./Navbar.module.scss";
import scrollIntoSection from "../../utils/scrollIntoSection";
import HamburgerIcon from "../../assets/navbar/Hamburger_Icon.svg";

const Navbar: React.FC<NavbarProps> = ({ navbarItems }) => {
    const [scrolled, setScrolled] = useState(false);

    useEffect(() => {
      const handleScroll = () => {
        setScrolled(window.scrollY > document.querySelector("#hero").offsetHeight);
      };
      window.addEventListener("scroll", handleScroll);
      return () => window.removeEventListener("scroll", handleScroll);
    }, []);

    return (
      <nav className={styles.stickyNav}>
        <div className="nav-container maxWidth_1200">
          <img src={navbar_logo} alt="Company logo" className="nav-logo-img-container" />
          <ul>
            {navbarItems.map((item, idx) => (
              <li key={idx} onClick={() => scrollIntoSection(item)}>{item}</li>
            ))}
          </ul>
        </div>
      </nav>
    );
};

type NavbarProps = { navbarItems: string[] };

export default Navbar;


When i try running this it shows some errors like: `You're importing a component that needs useEffect. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.

I expected next to handle ssr and csr implicitly, but if i decalre the component as "use client", that doesn't give the SEO benefits. Can someone suggest how do i use ssr and csr both at the same time.
Answered by Arinji
@Harlequin you can call client components from server components, it wont make a difference since either way your client component is getting server rendered once
View full answer

20 Replies

use client still is server prerendered
you can prove that by running your site and disabeling js (make sure you do actual start as dev is sometimes not as nice)
if you know pages dir, use client is basicly that... the RSC is a new thing that doesnt have the hydration on client
so basicly import your useclient and that small part will be clientable, and the rest will be easy work for client
HarlequinOP
any references @riský
@Harlequin any references <@657067112434499595>
HarlequinOP
Thanks
no problem, do you have any more questions about this?
HarlequinOP
Yes so just want to clear, then ssr is only useful when we need to use some service requiring secrets which shouldn't be exposed in browser, so the connections are made on server side. I can't think of any other usecase where we need it
its simpler, sends less stuff to client (as you just send basicly html instead of the react code and such), and you can use async function natively
also can do fetching on server with suspense for loading skeletons
HarlequinOP
Let's say i didn't had requirement for usestate, then using ssr vs csr what difference does each make
basicly what i said above (if it doesnt make sense feel free to say that)
and if you use no use hooks and anything client, you should just use server and make everything simpler (after all both ways are rendered on server, one just renders and sends code to client)
HarlequinOP
Thanks 🙂
HarlequinOP
@riský What if we abstract out the client functionality in separate component

"use client"
import React, { useEffect, useState } from 'react';
import styles from "./Navbar.module.scss";

const NavbarClient: React.FC = () => {
  const [scrolled, setScrolled] = useState(false);

  useEffect(() => {
    const handleScroll = () => {
      setScrolled(window.scrollY > document.querySelector("#hero").offsetHeight);
    };
    window.addEventListener("scroll", handleScroll);
    return () => window.removeEventListener("scroll", handleScroll);
  }, []);

  // Apply dynamic CSS class based on scroll state
  useEffect(() => {
    const nav = document.getElementById('nav');
    if (nav) {
      if (scrolled) {
        nav.classList.add(styles.scrolled);
      } else {
        nav.classList.remove(styles.scrolled);
      }
    }
  }, [scrolled]);

  return null;  // This component does not render anything itself
};

export default NavbarClient;



and we use this component in NavbarServer component, so that our html is rendered with rsc.
here is the NavbarServer component:
import React from 'react';
import navbar_logo from "../../assets/Vector.svg";
import styles from "./Navbar.module.scss";
import scrollIntoSection from "../../utils/scrollIntoSection";
import NavbarClient from './NavbarClient';

const NavbarServer: React.FC<NavbarProps> = ({ navbarItems }) => {
  return (
    <nav className={styles.stickyNav}>
      <div className="nav-container maxWidth_1200">
        <img src={navbar_logo} alt="Company logo" className="nav-logo-img-container" />
        <ul>
          {navbarItems.map((item, idx) => (
            <li key={idx} onClick={() => scrollIntoSection(item)}>{item}</li>
          ))}
        </ul>
        {/* Client-specific component that handles dynamic behaviors */}
        <NavbarClient />
      </div>
    </nav>
  );
};

type NavbarProps = { navbarItems: string[] };

export default NavbarServer;


What difference does it make?
@Arinji any comments?
@Harlequin you can call client components from server components, it wont make a difference since either way your client component is getting server rendered once
Answer
you cant call a server component from a client component tho, you can only import it as props and render that