1

I was reading the React docs and it recommended if you had some props that would be changed frequently, a good life cycle method to use would be shouldComponentUpdate.

My question is how would you use the useEffect approach with a functional component like the following?

This is my functional component:

function GenericIsUserLoggedInLink({ isLoggedIn, logOutUser, route, anchorText }) {

    const [setProps] = useState({isLoggedIn: isLoggedIn, route: route, anchorText:anchorText });
    console.log('setProps', setProps);

 useEffect((nextProps, nextState) => {
    if (setProps.isLoggedIn !== nextProps.setProps.isLoggedIn) {
      return true;
    }
    if (setProps.route !== nextProps.setProps.route) {
      return true;
    }
    if (setProps.anchorText !== nextProps.setProps.anchorText) {
      return true;
    }
    return false;
  });

 if (isLoggedIn) {
  if (anchorText === undefined) {
   return <Link href="/"><a onClick={() => logOutUser()}>Log out!</a></Link>
  } else if (anchorText) {
   return <Link href={route}><a >{anchorText}</a></Link>
  }
 } else {
  if (route === "/login") {
     return  <Link href="/login"><a >Log in!</a></Link>
  }
  return null
 }
}

That was my take, but it didn't work! HA! Is there anyone who can provide insight?

UPDATE I followed Shubham's prescription—but ran into this?

enter image description here

SO i did this... But it feels hacky: I guess its not as I am leveraging lexical scoping

var comparator;
const GenericIsUserLoggedInLink = React.memo(({ isLoggedIn, logOutUser, route, anchorText }) => {
 comparator = (prevProps, nextProps) => {
  if (prevProps.isLoggedIn !== nextProps.setProps.isLoggedIn) {
      return true;
    }
    if (prevProps.isLoggedIn !== nextProps.setProps.route) {
      return true;
    }
    if (prevProps.anchorText !== nextProps.setProps.anchorText) {
      return true;
    }
    return false;
}

   if (isLoggedIn) {
      if (anchorText === undefined) {
       return <Link href="/"><a onClick={() => logOutUser()}>Log out!</a></Link>
      } else if (anchorText) {
       return <Link href={route}><a >{anchorText}</a></Link>
      }
   } else {
      if (route === "/login") {
         return  <Link href="/login"><a >Log in!</a></Link>
      }
      return null
   }
}, comparator);
Antonio Pavicevac-Ortiz
  • 7,239
  • 17
  • 68
  • 141
  • I am not sure if the return true/false in useEffect has any thing to do with the component rendering. Because, if we return a function in useEffect, it will be run as a clean up function, however, I don't think it has anything to do with a boolean. – Leela Venkatesh K Oct 16 '19 at 04:47
  • also, I am not sure if the nextProps would be available inside a useEffect or not. So, I would leave it to better people to clarify – Leela Venkatesh K Oct 16 '19 at 04:49
  • Why would you need that "setProps" state and those checks in a first place? You never use that state in render phase and you useEffect does nothing useful. What does go wrong if you just leave `if (isLoggedIn) { ... }` part? – Vlad Glazov Oct 16 '19 at 06:07

1 Answers1

2

useEffect is not an appropriate hook as an alternative to shouldComponentUpdate for functional components.

Rather you need to use React.memo in order to prevent re-rendering. Also you don't need to maintain a state to compare previous and current props.

const comparator = (prevProps, nextProps) => {
  if (prevProps.isLoggedIn !== nextProps.setProps.isLoggedIn) {
      return true;
    }
    if (prevProps.route !== nextProps.setProps.route) {
      return true;
    }
    if (prevProps.anchorText !== nextProps.setProps.anchorText) {
      return true;
    }
    return false;
}

const GenericIsUserLoggedInLink = React.memo(({ isLoggedIn, logOutUser, route, anchorText }) => {

   if (isLoggedIn) {
      if (anchorText === undefined) {
       return <Link href="/"><a onClick={() => logOutUser()}>Log out!</a></Link>
      } else if (anchorText) {
       return <Link href={route}><a >{anchorText}</a></Link>
      }
   } else {
      if (route === "/login") {
         return  <Link href="/login"><a >Log in!</a></Link>
      }
      return null
   }
}, comparator);
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • 1
    Thanks so much! I really appreciate it! I updated my question with your addition and what happened subsequently. So `React.memo` should speed things up? I imagine in `production` this would be speedier? – Antonio Pavicevac-Ortiz Oct 16 '19 at 15:13
  • 2
    Watch out for the comparator function. When it returns true the component will not be re-redered. Call it areEqual or shouldNotRerender for better understanding. – Watchmaker May 15 '20 at 20:43