Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does React re-render differently whether the state is an object vs a string?

Tags:

reactjs

The below React example, userProfile state is an object:
1st render: state is {}
2nd render: state is res.data
-> infinite re-rendering

If userProfile is changed to a string e.g. useState('') with setUserProfile(res.data.bio)
1st render: state is ''
2nd render: state is res.data.bio
3rd render: state is res.data.bio
-> stops re-rendering after the 3rd

Two questions:

  • Why does React re-render differently depending on whether userProfile state is an object vs a string?
  • When userProfile is a string, why does React stop re-rendering after the 3rd render instead of after the 2nd one?

App.js

import UserProfile from './UserProfile';

const App = () => {
    const login = 'facebook';
    
    return (
        <Router>
            <Link to={`/user/${login}`}>Fetch Facebook bio from GitHub</Link>
            <Route path='/user/:login' component={UserProfile} />
        </Router>
    );
};

UserProfile.js

const UserProfile = ({ match }) => {
    const [userProfile, setUserProfile] = useState({});

    const getUser = async username => {
        const url = `https://api.github.com/users/${username}`;
        const res = await axios.get(url);
        setUserProfile(res.data);
    };

    getUser(match.params.login);
// intentionally not using useEffect(() => { getUser(match.params.login); }, []);

    return (<p>{userProfile.bio}</p>);
};

1 Answers

React checks if a state variable has changed, and if so, it rerenders. Since no matter how many times you compare two objects (even if they look identical), they will always be different, React will keep rerendering.

A string, on the other hand, is a primitive type and thus compares differently. Try this:

console.log({d: 3} === {d: 3})
console.log("sss" === "sss")

And it will give you an idea as to why this happens.

So even though you keep setting the state var to the same object, it's not really the same. But a string IS the same so it stops rerendering.

Check out this article on Object equality in JS: http://adripofjavascript.com/blog/drips/object-equality-in-javascript.html

Now let me address your second question:

When userProfile is a string, why does React stop re-rendering after the 3rd render instead of after the 2nd one?

If you look at the React Docs, you will run into these 2 paragraphs, which, I believe answer your question:

If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the Object.is comparison algorithm.)

Note that React may still need to render that specific component again before bailing out. That shouldn’t be a concern because React won’t unnecessarily go “deeper” into the tree. If you’re doing expensive calculations while rendering, you can optimize them with useMemo

Note the second paragraph.

like image 147
codemonkey Avatar answered Jul 08 '26 02:07

codemonkey



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!