Search code examples
reactjsnext.jsserver-side-renderingvercel

NextJS SSR and Client side state


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);


Solution

  • 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,
        },
      };
    }