简体   繁体   中英

Do react functional and class components render differently?

When I use a react functional component with some state manager (I'm using recoil.js) and I try to update the state with a react hook it only calls useEffect when the state is different than the original state. When I was looming on stack overflow on how components rerender, they were talking about class components, and how they render every time setState is called. Is this just a difference between how the two components type work or am I just misunderstanding it?

This was my code test for function components:

import React, {useEffect} from 'react'
import ReactDOM from 'react-dom'
import {atom, useRecoilState, RecoilRoot} from 'recoil'

ReactDOM.render(
    <React.StrictMode>
        <RecoilRoot>
            <App />
        </RecoilRoot>
    </React.StrictMode>,
    document.getElementById('root')
);

const testAtom = atom({
    key: "test",
    default: ""
});

function App(){
    return (
        <>
            <C1 />
            <C2 />
        </>
    );
}

function C1(){
    const [test, setTest] = useRecoilState(testAtom);
    
    useEffect(() => {
        console.log('effected', 'c1');
    });
    
    return (
        <div>
            <button onClick={() => {setTest('c1')}}>Click me</button>
        </div>
    );
}

function C2(){
    const [test, setTest] = useRecoilState(testAtom);
    
    useEffect(() => {
        console.log('effected', 'c2');
    });
    
    return (
        <div>
            <button onClick={() => {setTest('c2')}}>Click me</button>
        </div>
    );

}

Running this useEffect is only called when the state is changed, not just when setTest is called, but this person said otherwise for class components.

React doesn't compare state data. When setState is called, it marks the component as dirty (which means it needs to be re-rendered).

Does this mean if I were to make this a class component that it would conoslelog every time?

Yes and no. I wouldn't say "they render differently", but there is a difference between how it is determined when to renrender a component. I understand how one could expect that the default behavior is the same, however, I also understand that introducing a new state system ( useState ) gave the developers an opportunity to improve the default behavior.

I don't know how recoil works specifically, but I would assume it behaves at least like useState wrt rerendering the component. From the documentation :

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 .)

So this confirms your observation.

But let me be clear: This is not a characteristic of function components, that's just how useState works. You could develop your own state management hook which behaves differently.

Now looking add class components, from the setState documentation :

setState() will always lead to a re-render unless shouldComponentUpdate() returns false

And about shouldComponentUpdate :

Use shouldComponentUpdate() to let React know if a component's output is not affected by the current change in state or props. The default behavior is to re-render on every state change, and in the vast majority of cases you should rely on the default behavior.

shouldComponentUpdate() is invoked before rendering when new props or state are being received. Defaults to true .

The first part isn't as clear ( "The default behavior is to re-render on every state change" , but is setting the same value a "change"?), but the second paragraph makes it clear. shouldComponentUpdate returns true by default, so the component will always rerender when setState was called.

If you implement shouldComponentUpdate to call Object.is you would replicate the behavior of useState .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM