NextJS SSR and Client side state

Viewed 1254

I have the following nextJS app:


export default function Home({ productsData }) {
  const [user, setUser] = useState(null);
  const [products, setProducts] = useState([]);

  useEffect(() => {
    if (productsData) setProducts(productsData);
  }, [productsData]);

  useEffect(() => {
    const userLocal = window.localStorage.getItem("user");
    if (userLocal) {
      setUser(JSON.parse(userLocal));
    }
  }, []);

  return (
    <div className="container">
      <ul className="row">
        {products.map((product) => {
          return (
            <h1>
              {product.translation.name} -{" "}
              {user
                ? user.premium
                  ? product.prices.premium
                  : product.prices.price
                : product.prices.price}
            </h1>
          );
        })}
      </ul>
    </div>
  );
}

export async function getServerSideProps() {
  const data = [
    {
      prices: {
        premium: 25,
        price: 59.95,
      },
      translation: {
        name: "Product 1",
      },
    },
    {
      prices: {
        premium: 25,
        price: 29.95,
      },
      translation: {
        name: "Product 2",
      },
    },
  ];
  return {
    props: {
      productsData: data,
    },
  };
}

This works but if I do a "curl" request to localhost I dont see that the server is rendering anything, that is because useEffect setting "products" happen on the Client side.

But if I do this: const [products, setProducts] = useState(productsData);

Then I have this error: Error: Hydration failed because the initial UI does not match what was rendered on the server. - Buscar con Google

So, do I have to choose between SSR and having the state in the client side?

I tried const [products, setProducts] = useState(productsData);

2 Answers

you dont need useEffect this time !

you can use Loading for this

export default function Home({ productsData }) {
  const [user, setUser] = useState(null);
  

  useEffect(() => {
    const userLocal = window.localStorage.getItem("user");
    if (userLocal) {
      setUser(JSON.parse(userLocal));
    }
  }, []);

  return (
    <div className="container">
      <ul className="row">
        {productsData?.map((product) => {
          return (
            <h1>
              {product.translation.name} -{" "}
              {user
                ? user.premium
                  ? product.prices.premium
                  : product.prices.price
                : product.prices.price}
            </h1>
          );
        })}
      </ul>
    </div>
  );
}

export async function getServerSideProps() {
  const data = [
    {
      prices: {
        premium: 25,
        price: 59.95,
      },
      translation: {
        name: "Product 1",
      },
    },
    {
      prices: {
        premium: 25,
        price: 29.95,
      },
      translation: {
        name: "Product 2",
      },
    },
  ];
  return {
    props: {
      productsData: data,
    },
  };
}

I strongly recommend TanStack Query (formerly ReactQuery) for this kind of scenario.

You can take advantage of SSR, client fetching, etc. TanStack Query is just a cache layer between NextJS and your data.

They have a SSR guide with NextJS in their docs.

Related