Can I use UseState with Server-Side-Rendering?
Asked Answered
T

4

8

Can you use useState (and other react hooks?) with Server Side Rendering? Every time I am trying to run the code below I get the error

TypeError: Cannot read property 'useState' of null.

However, when I comment out the getServerSideProps function at the very bottom I have no problem running the code as intended. So my questions is can useState be used with Server Side Rendering in Nextjs? If the answer is yes, then where am I going wrong in the code below?

 import React from "react";
    import { useRouter } from "next/router";
    import useSelectedGenreInfoExtractor from "../../hooks/useSelectedGenreInfoExtractor";
    import { useState } from "react";
    import { useEffect } from "react";
    import Navbar from "../../components/Navbar";
    import useFetchTrendingCatagory from "../../hooks/useFetchTrendingCatagory";
    import useFetchTopRatedCatagory from "../../hooks/useFetchTopRatedCatagory";
    import useFetchMovieGenreResults from "../../hooks/useFetchMovieGenreResults";
    import Moviegenreresults from "../../components/Moviegenreresults";
    
export default function genre(props) {
      const [myresultsfromhook, setMyresultsfromhook] = useState();
      const [myreturnedmovies, setMyreturnedmovies] = useState();
    
      const router = useRouter();
      const { genre } = router.query;
    
      if (genre == "Trending") {
        let mymovies = useFetchTrendingCatagory();
        console.log("This is a log of my props", props);
    
        return (
          <div>
            {/* <Navbar /> */}
            <div>{genre}</div>
            <Moviegenreresults movies={mymovies} />
          </div>
        );
      } else if (genre == "Top Rated") {
        let mymovies = useFetchTopRatedCatagory();
    
        return (
          <div>
            {/* <Navbar /> */}
            <div>{genre}</div>
            <Moviegenreresults movies={mymovies} />
          </div>
        );
      } else {
        let mymovies = useFetchMovieGenreResults(genre);
    
        return (
          <div>
            {/* <Navbar /> */}
            <div>{genre}</div>
            <Moviegenreresults movies={mymovies} />
          </div>
        );
      }
    }
    
    export async function getServerSideProps(context) {
      if (context.params.genre == "Trending") {
        let mymovies = useFetchTrendingCatagory();
        return {
          props: {
            results: mymovies.results,
          },
        };
      } else if (context.params.genr == "Top Rated") {
        let mymovies = useFetchTopRatedCatagory();
        return {
          props: {
            results: mymovies.results,
          },
        };
      } else {
        let mymovies = useFetchMovieGenreResults(genre);
        return {
          props: {
            results: mymovies.results,
          },
        };
      }
    }
Thermomotor answered 29/8, 2022 at 2:9 Comment(1)
You can't use hooks in getServerSideProps. See #64203334.Seigniorage
I
3

useState should be inside the component, it is a React hook. serverside functions are independent of React components.

I think the issue is the name of the component should be with capital letter:

 // not genre
 export default function Genre(props)
Ina answered 29/8, 2022 at 3:56 Comment(2)
useState is already inside the component. The problem is that the component is a server component, where useState isn't usable.Eremite
@CameronHudson i think originally the question haf ‘useState’ in the ‘getServerSideProp’ function. If you read the question, if he comments out server function error was goneIna
A
1

I think fundamentally the problem is the way you are using getServerSideProps.

Even thought the answer is you can not use useState inside getServerSideProps because this function run in the server, it is important to understand what getServerSideProps does and when, I think you can find very clear explanation about that in next docs.

https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props

Inside getServerSideProps use axios or the fetch api to get your data and pass it to the props.

I am not 100% sure but I thinnk inn your case you can also use Promise.all() to get the data from those three api calls.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Antimonyl answered 29/8, 2022 at 2:22 Comment(4)
So just to be clear, are you saying I cannot use useState on the same page I use getServerSideProps on? Or are you saying I can not use useState INSIDE the getServerSideProps functions (because I did not in the example). Also, is it possible that instead of using axios or fetch inside getServerSideProps, that I use custom Hooks? I think this should be possible as I don't see a difference between using custom hooks or writing my functions directly inside the getServerSideProps function.Thermomotor
My bad, I thought you were using useState inside useFetchMovieGenreResults. Because I can not see you are using myresultsfromhook, myreturnedmovies anywhere else. Also, what are you returning from useFetchMovieGenreResults and why are you using it in getServerSideProps and inside the components aswell? Plus I don't see you using your props any where on the template.Antimonyl
@Thermomotor "Also, is it possible that instead of using axios or fetch inside getServerSideProps, that I use custom Hooks?" - That is not possible because hooks need React and only work in function components and/or other React hooks. getServerSideProps is just a special function that runs on the server (no React available).Leon
@Thermomotor "are you saying I can not use useState INSIDE the getServerSideProps functions (because I did not in the example)" - You may not be using useState directly in getServerSideProps but my guess is that the custom hooks you call in there have useStates somewhere inside them. Hence why your error occurs.Leon
J
0

Ran into similar issue, but the solution ended up different so posting it here in case someone benefits in future.

Basically, one of the causes for TypeError: Cannot read property 'useState' of null can be React loaded multiple times and because of that unable to track properly if the hook is within the component.

There is a lot more details here and here and the root cause could be very different but likely to do with how the code is bundled. In my specific case, I had a separate folder for SSR code and shared code, and both of these had separate react and react-dom installed in their package.json. Removing the react and react-dom from the SSR specific folder and just reusing the shared one fixed the issue

Juglandaceous answered 16/4, 2023 at 19:1 Comment(0)
C
0

The problem with this code is that you're using React hooks (useFetchTrendingCatagory, useFetchTopRatedCatagory, useFetchMovieGenreResults) inside the getServerSideProps function, which is not allowed. React hooks can only be used within React functional components or custom hooks. You should refactor your code to fetch data synchronously inside getServerSideProps using regular JavaScript functions or by using a data fetching library like axios or fetch.

Convector answered 5/4 at 17:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.