Home > Software design >  re-render not behaving properly
re-render not behaving properly

Time:09-29

So I deployed the app to demonstrate the problem https://ecstatic-mayer-aaa530.netlify.app/ When you 'refresh' the page new data is fetched and user name is displayed (along with active state) BUT when I click random user button, I don't get the same behavior even though I refetch the data. I want to get the same behavior as page refresh. (Name is displayed with the active state) To better observe the problem you can : Hover on other fields, click on random user btn and then re-enter with your mouse on name (profile icon). It is not updating as you'll see

import './App.css';
import ProfileCard from './components/ProfileCard';
import React, { useEffect, useState } from 'react';

function App() {
    const [userData, setUserData] = useState({});
    const [triggerFetch, setTriggerFetch] = useState(false);

    const fetchUserData = async () => {
        const response = await fetch('https://randomuser.me/api/');
        const data = await response.json();
        setUserData(setFields(data.results[0]));
    };

    const setFields = (userData) => {
        const fName = userData.name.first;
        const lName = userData.name.last;
        const fullName = fName   ' '   lName;
        return {
            image: userData.picture.large,
            name: fullName,
            email: userData.email,
            dob: userData.dob.date,
            location: userData.location.street.name,
            phone: userData.phone,
            password: userData.login.password,
        };
    };

    useEffect(() => {
        fetchUserData();
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [triggerFetch]);

    //this triggers fetch
    const handleRandomUserClick = () => {
        setTriggerFetch(!triggerFetch);
    };

    return (
        <main>
            <div className='grey-bg'></div>

            <ProfileCard
                userData={userData}
                handleRandomUserClick={handleRandomUserClick}
            />
        </main>
    );
}

export default App;
   import React from 'react';
   import {
       FaUserAlt,
       FaPhoneAlt,
       FaBirthdayCake,
       FaLock,
       FaLocationArrow,
       FaEnvelope,
   } from 'react-icons/fa';
   
   const ProfileCard = ({ userData, handleRandomUserClick }) => {
       const { image, name, email, dob, location, phone, password } = userData;
   
       const [randomUserClicked, setrandomUserClicked] = React.useState(false);
   
       const defaultFlag = {
           name: 'active',
           email: '',
           dob: '',
           location: '',
           phone: '',
           password: '',
       };
   
       const [flag, setFlag] = React.useState(defaultFlag);
       const [title, setTitle] = React.useState('My Name Is');
       const [value, setValue] = React.useState(name);
   
       const handleValue = (e) => {
           if (e.target.dataset.label === 'name') {
               setTitle('My Name is');
               setValue(name);
               setFlag(defaultFlag);
           } else if (e.target.dataset.label === 'email') {
               setTitle('My Email is');
               setValue(email);
               setFlag({
                   name: '',
                   email: 'active',
                   dob: '',
                   location: '',
                   phone: '',
                   password: '',
               });
           } else if (e.target.dataset.label === 'dob') {
               setTitle('My Birthday is');
               setValue(new Date(dob).toLocaleDateString());
               setFlag({
                   name: '',
                   email: '',
                   dob: 'active',
                   location: '',
                   phone: '',
                   password: '',
               });
           } else if (e.target.dataset.label === 'location') {
               setTitle('I live in');
               setValue(location);
               setFlag({
                   name: '',
                   email: '',
                   dob: '',
                   location: 'active',
                   phone: '',
                   password: '',
               });
           } else if (e.target.dataset.label === 'phone') {
               setTitle('My phone number is');
               setValue(phone);
               setFlag({
                   name: '',
                   email: '',
                   dob: '',
                   location: '',
                   phone: 'active',
                   password: '',
               });
           } else {
               setTitle('My password');
               setValue(password);
               setFlag({
                   name: '',
                   email: '',
                   dob: '',
                   location: '',
                   phone: '',
                   password: 'active',
               });
           }
   
           if (e.target.dataset.label === 'random') {
               handleRandomUserClick();
               setrandomUserClicked(!randomUserClicked);
           }
       };
   
       React.useEffect(() => {
           setTitle('My Name is');
           setValue(name);
           setFlag(defaultFlag);
       }, [randomUserClicked]);
   
       return (
           <article className='profile-card'>
               <img src={image} alt={name} />
   
               <div className='user-details'>
                   <p className='user-title'>{title}</p>
                   <h3 className='user-value'>{value || name}</h3>
               </div>
   
               <ul className='card-list'>
                   <li className={flag.name} onMouseEnter={handleValue} data-label='name'>
                       <FaUserAlt className='icon' />
                   </li>
                   <li
                       data-label='email'
                       onMouseEnter={handleValue}
                       className={flag.email}
                   >
                       <FaEnvelope className='icon' />
                   </li>
                   <li data-label='dob' onMouseEnter={handleValue} className={flag.dob}>
                       <FaBirthdayCake className='icon' />
                   </li>
                   <li
                       data-label='location'
                       onMouseEnter={handleValue}
                       className={flag.location}
                   >
                       <FaLocationArrow className='icon' />
                   </li>
                   <li
                       data-label='phone'
                       onMouseEnter={handleValue}
                       className={flag.phone}
                   >
                       <FaPhoneAlt className='icon' />
                   </li>
                   <li
                       data-label='password'
                       onMouseEnter={handleValue}
                       className={flag.password}
                   >
                       <FaLock className='icon' />
                   </li>
               </ul>
               {/* Also handling this click within handleValue function */}
               <button className='btn' onClick={handleValue} data-label='random'>
                   Random User
               </button>
           </article>
       );
   };
   
   export default ProfileCard;

CodePudding user response:

The problem happens, because in ProfileCard component, userData is not listed under useEffects's dependencies array.


By the way, your component design is very prone to bugs. In React functional components should be a simple functions that receive some data (props) and return JSX. Hooks should be used only when you actually have to use them. In your app, you're creating a complicated network of effects, state updates and re-renders, which makes it hard to maintain.

Let's write all hooks you actually need:

  • one state for the data fetched from an api
  • one state for keeping which section is currently active (name, email, etc.)
  • one effect for fetching the data

And that's it! Everything else can be just passed through props.

  • Related