user8758206
user8758206

Reputation: 2191

Very simple react destructuring issue with a custom hook

I'm amazed that I can't solve this myself, but I'm having a basic issue here. Essentially I just want to destructure the user variable in the useSetWelcome hook to prevent the use of verbose chaining such as user.user.email - for instance, const { email } = user does not work and instead needs user.user.

I tried changing from const useSetWelcome = user => { to const useSetWelcome = ({ user }) => {, but that results in an infinite loop.

Where am I going wrong here? My code demo: https://stackblitz.com/edit/react-b1jroe

And the code:

import React, { useState, useEffect } from 'react';

const joe = {
  name: 'Joe',
  email: '[email protected]'
};

// const useSetWelcome = ({ user }) => { // infinite loop problem
const useSetWelcome = user => {
  const [name, setName] = useState(null);
  const [welcomeMsg, setWelcomeMsg] = useState('No user detected');
  // const { email } = user; // needs user.user
  // console.log('user', user);
  // console.log('{user}', { user });
  // console.log('user.email', user.email); // should be [email protected]
  // console.log('email', email); // should be [email protected]
  console.log('user?.user?.email', user?.user?.email); // works

  if (user.name) {
    setName(user.name);
    setWelcomeMsg('welcome ' + user.name);
  }

  return { name, welcomeMsg };
};

const App = () => {
  // const [user, setUser] = useState(joe); // joe or {joe}? and why?
  const [user, setUser] = useState(joe);
  console.log('state user', user);

  const toggleLogin = user => {
    if (user) {
      setUser(null);
    } else {
      setUser(joe);
    }
  };

  const loginMsg = user ? 'Logout' : 'Login';

  const Welcome = user => {
    const { name, welcomeMsg } = useSetWelcome(user);
    return (
      <p>
        {welcomeMsg} {name}
      </p>
    );
  };

  return (
    <div>
      <Welcome user={user} />
      <button onClick={() => toggleLogin(user)}>{loginMsg}</button>
    </div>
  );
};

export default App;

Upvotes: 0

Views: 710

Answers (1)

Sagi Rika
Sagi Rika

Reputation: 2979

The problem is, <Welcome /> is a component. A component receives only one parameter, props. So, when you write this: const Welcome = user => {, its actually const Welcome = props => {.

Long story short, change this line to const Welcome = ({ user }) => { (so you destruct user from props) and it will work.

P.S.: You're getting an infinite loop because inside your useSetWelcome hook, you have this condition:

if (user.name) {
  setName(user.name)
}

When you use setName, the entire hook rerenders, and the condition is tested again. Again, user.name will exist, and setName will get called again, and again, and forever. To achieve what I think you intended to, you have to improve the condition to something like this:

if (user.name && user.name !== name) {
    setName(user.name);
    setWelcomeMsg('welcome ' + user.name);
}

Upvotes: 3

Related Questions