Vikalp Jain
Vikalp Jain

Reputation: 603

Not able to pass Props to Component - Inconsistent Behavior

I have a React.js and Next.js app where I need to pass the User object to all the pages. I then plan to pass this User component to Head component so that I can show different navigation based on user role. This is what I have so far:

This is _App.js where I check if user token exists. If it exists, I verify it by calling an API and then I assign the result to pageProps. This pageProps is then passed to other components.

import '../styles/global.css'
import CustomTheme from '../styles/custom-theme';
import { ThemeProvider } from '@material-ui/styles';
import { getToken, setUserSession } from '../utils/common';
import React, { useState, useEffect } from 'react';

function MyApp({ Component, pageProps }) {

  useEffect(()=>{
    const token = getToken();
    console.log(token)
    if (!token){
      console.log('no token')
      return;
    }

    const requestOptions = {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'x-access-token': token },
      //body: token
    };

    fetch("http://localhost:3600/auth/verifyToken", requestOptions)
      .then(res => res.json())
      .then(
          (result) => {
            pageProps.user = JSON.stringify(result);
            console.log('verifyToken response 2 : ' + JSON.stringify(result))
      })
  },[])

  console.log(pageProps)
  return (
  <ThemeProvider theme={CustomTheme}>
    {/* <Component {...pageProps} /> */}
    <Component {...pageProps} />
  </ThemeProvider>
  )
}

export default MyApp

Then, in my waiting-room.js page, I try to get hold of this prop and print it:

export default function WaitingRoom(pageProps) {
const classes = useStyles();
const [selectedValue, setSelectedValue] = useState('yes');
const [error, setError] = useState(null);
const [isLoaded, setIsLoaded] = useState(false);
const [userId, setUserId] = useState(null);
const [childName, setChildName] = useState(null);
const [demoData, setDemoData] = useState(null);
const [counterTime, setCounterTime] = useState(null);
const [disableJoin, setDisableJoin] = useState(true);
const [classOver, setClassOver] = useState(false);
const [demoBooked, setDemoBooked] = useState(false);

// Note: the empty deps array [] means
// this useEffect will run once
// similar to componentDidMount()
useEffect(() => {
  console.log("pageProps : " + JSON.stringify(pageProps.user))
})
}

First time page load, everything is fine. All console.log statements print values as expected. But when I click on browser refresh button, I see pageProps as undefined. And then when I again make some changes on the page and save it, it starts working till I again hit browser refresh. Is it something to do with server side rendering?

Edit post @Siddhart's answer:

Console.log after server refresh

React Dev tools component view after server refresh

Console.log after Browser refresh. pageProps are gone

React Dev tools component view after Browser refresh. pageProps are there.

Upvotes: 0

Views: 152

Answers (1)

Siddharth
Siddharth

Reputation: 1270

You're seeing the weird behavior because you're mutating the original pageProps object.


Reason why you're not seeing the pageProps changes

WaitingRoom isn't aware of any change because reference to the pageProps remain same.


Reason why you see the pageProps changes

Probably MyApp component re-renders due to some prop change which in turn causes the re-render of child component i.e. WaitingFroom

What you need to do is, update state when pageProps changes so that component re-renders with updated props.

import '../styles/global.css'
import CustomTheme from '../styles/custom-theme';
import { ThemeProvider } from '@material-ui/styles';
import { getToken, setUserSession } from '../utils/common';
import React, { useState, useEffect } from 'react';

function MyApp({ Component, pageProps }) {
 
  const [updatedProps, setUpdatedProps] = useState(pageProps);
  
  // If pageProps change over time
  useEffect(() => {
     setUpdatedProps(prevUpdatedProps => ({
      ...prevUpdatedProps,
      ...pageProps
    }));
  }, [pageProps])


  useEffect(()=>{
    const token = getToken();
    console.log(token)
    if (!token){
      console.log('no token')
      return;
    }

    const requestOptions = {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'x-access-token': token },
      //body: token
    };

    fetch("http://localhost:3600/auth/verifyToken", requestOptions)
      .then(res => res.json())
      .then(
          (result) => {
            pageProps.user = JSON.stringify(result);
            setUpdatedProps({...updatedProps, user: JSON.stringify(result)});
            console.log('verifyToken response 2 : ' + JSON.stringify(result))
      })
  },[])

  return (
  <ThemeProvider theme={CustomTheme}>
    <Component {...updatedProps} />
  </ThemeProvider>
  )
}

export default MyApp

Upvotes: 2

Related Questions