Search code examples
javascriptreactjsnext.jsserver-side-rendering

How to pass fetched data to getServerSideProps function?


I'm using Context API to fetch data and then pass data to getServerSideProps function but I'm having the following error:

React Hook "useContext" is called in function "getServerSideProps" that is neither a React function component nor a custom React Hook function

Here's my code:

AppContext.tsx:

export const AppContext = createContext(null);
export const AppContextProvider = ({ children }) => {
  const [data, setData] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      const response = await fetch('http://localhost:8080/api/users');
      const body = await response.json();
      setData(body.users);
    };
    fetchData();
  }, []);
  return (
    <AppContext.Provider value={data}>{children}</AppContext.Provider>
  );
};

Then in my index.tsx file (path: apps/ui/pages/index.tsx) I have this code:

const Home: NextPage<HomeProps> = ({ tiers }) => {
  const data = useAppContext();
  console.log('data', data); // This prints the data just fine

  return (
    <Box>
      <Head>
        <title>React App</title>
      </Head>
      {data?.map((user) => (
        .....
        />
      ))}
    </Box>
  );
};

export async function getServerSideProps() {
  // const data = useContext(AppContext); // Here I get the error message I mentioned above
  return {
    props: {
      data,
    },
  };
}

export default Home;

so How can I receive the data coming from my Context file inside my getServerSideProps function and NOT having to use the context straight in my Home component?

NOTE: I do have a partial fix, BUT I don't want to do it in index.tsx file because I want the data to come from my Context.

Here's my partial fix, in index.tsx I have this function:

const fetchData = async () => {
  const response = await fetch('http://localhost:8080/api/users');
  const body = await response.json();
  return body.users;
};

and inside getServerSideProps function I have this:

export async function getServerSideProps() {
  const data = await fetchData();

  return {
    props: {
      data,
    },
  };
}

and inside Home component I'm just passing it as a prop like this:

const Home: NextPage<HomeProps> = ({ data }) => (..)


Solution

  • What @code is saying is correct, you have a context that fetches data clientside and you want to use this data in getServerSideProps. You are trying to magically pass clientside data to the server without making a request. The problem here is that you are misinterpreting the data flow with getServerSideProps.

    With getServerSideProps you generate some data (props) on the server and then pass them to to the page so react can render on the server.

    getServerSideProps only runs when you request the page (a GET request) and it runs before any react code, hence why you cannot access your context data.

    The partial solution you have is correct but instead of making a fetch call, import the logic from this route /api/users inside getServerSideProps. This will save you a duplicate call to your server.