Why React Re-Renders
Discussion 1
Today, I will talk about some topics in React that should be considered for developing an optimized and scalable website in React.
Part 1: Re-rendering Issue
Consider the following code snippet:
const [showModal, setShowModal] = useState(false);
return (
<div className={styles.column}>
{showModal ? (
<Modal
show={showModal}
handleClose={() => setShowModal(false)}
/>
) : null}
<KanbanBoard />
<Column />
</div>
);
In this example, a modal is shown conditionally based on state changes. When the state changes, the whole component re-renders, regardless of how expensive other components might be. You might think of implementing a custom hook to handle this, like so:
领英推荐
const useModal = () => {
const [isOpen, setIsOpen] = useState(false);
return {
isOpen,
open: () => setIsOpen(true),
close: () => setIsOpen(false),
toggle: () => setIsOpen(!isOpen)
};
};
Now, you use this in your component:
const { isOpen, toggle } = useModal();
return (
<div className={styles.column}>
{isOpen ? (
<Modal
show={isOpen}
handleClose={toggle}
/>
) : null}
<KanbanBoard />
<Column />
</div>
);
This will also cause re-renders because the state is still changing, which triggers a re-render. Although the state change is managed in the custom hook, it can still affect the component. Note that custom hooks can sometimes be dangerous because if you have a hook that records the screen size internally and you import that hook into other components, every state change will cause re-renders in those components.
Solution: The solution is to isolate the state changes of each component separately. For example:
const ModalWithButton = ({ title, todos, addTodo, moveTodo }) => {
const [showModal, setShowModal] = useState(false);
return (
<div className={styles.column}>
{showModal ? (
<Modal
show={showModal}
handleClose={() => setShowModal(false)}
/>
) : null}
<button onClick={() => setShowModal(true)}>Open Modal</button>
</div>
);
};
export default ModalWithButton;
In the above component, you isolate the modal state completely in a different component and import this where you need it. Now, the state changes and re-rendering will only affect the ModalWithButton component, improving performance. This approach helps ensure that re-renders are confined to the specific component that requires state changes, reducing unnecessary re-renders and enhancing overall performance.
Software engineer | Frontend | Fullstack | Web Accessibility | I help teams that wish to build frustration-free UI
8 个月One easy way to suppress *unnecessary* re-renders in the example you gave is to change the design to be fully event-driven without storing the modal dialog state anywhere. To do this you will need to make the following changes: 1. Change the modal implementation to use a <dialog> element. 2. Change the button's click handler so it doesn't update the state, but calls showModal() on the dialog element. 3. Change the modal's close button click handler to call close() on the dialog element. Since, in your case, the button that opens the modal isn't located in the same component as the <dialog> you can use a (global) event bus to establish communication between the button and the dialog. The window object is already an event bus, so that shouldn't be too hard. Imo, the modal should be a <dialog> element anyway, so I think this solution is a natural consequence of making the modal component use it.