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:
userProfile state is an object vs a string? 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>);
};
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With