React rerender full tree of the component

Viewed 274

I have a component:

export const Filters: FC = observer(() => (
    <div className={`filters ${viewModel.isDragged ? 'filters--dragged' : ''} ${!viewModel.isOpened ? 'filters--collapsed' : ''}`}
         style={viewModel.position}>
        <FiltersHeader/>
        <FiltersBody/>
    </div>
));

This component is decorated with observer from mobx-react-lite. Field position is decorated with @observable decorator from mobx package. position is consist of field left: number and top: number.

I want to drag this component. And to achieve it I reinisialize position when user triggers mousemove.

The problem is <FiltersHeader/> and <FiltersBody/> not small components, it takes a while to render them. And each time I change viewModel.position React rerender entire tree. Not only FiltersHeader and FiltersBody, also their children and their children, etc.

Why does React do that? I mean, FiltersHeader has no properties. React should not rerender the component again if its properties did not change. Or should it?


This code works the same

export const Filters: FC = () => {
    const [position, setPosition] = useState(viewModel.position);
    useEffect(() => {
        reaction(() => viewModel.position, value => setPosition(value));
    }, []);
    return (
        <div className={`filters ${viewModel.isDragged ? 'filters--dragged' : ''} ${!viewModel.isOpened ? 'filters--collapsed' : ''}`}
             style={position}>
            <FiltersHeader/>
            <FiltersBody/>
        </div>
    );
}
1 Answers

As other commenter said, React does not apply optimizations by default, so every child component will rerender (even if it has no props) when parent component does.

You can wrap them in React.memo or actually wrap in observer too, because it also applies memo automatically.

Related