Single Responsibility Principle
Meaning one "thing" should only concern about doing one thing properly. This "one thing" can be a React Component, a function or a module, etc.
Examples
If you need a feedback form in a pop-up, the form and the pop-up modal should not be one single component. Both should be independent pieces of code. These should not be tightly coupled with each other.
function FeedbackPopup() {
const [isOpen, setIsOpen] = React.useState(false);
const open = () => setIsOpen(true);
const close = () => setIsOpen(false);
if (!isOpen) {
return <button onClick={open}>Give Feedback</button>;
}
return (
<div>
<h2>Feedback</h2>
<textarea placeholder='Your feedback here...'></textarea>
<button onClick={close}>Close</button>
</div>
);
}
In this code nothing is re-usable, and its completely resistant to change.
// file: modal.tsx
function Modal({ isOpen = false, close, title = 'Modal Title', children }) {
if (isOpen) return null;
return (
<div>
<h2>{title}</h2>
<main>{children}</main>
</div>
);
}
// file: feedbackForm.tsx
function FeedbackForm({ onSubmit, onCancel }) {
return (
<form>
<textarea placeholder='Your feedback here...'></textarea>
<button onClick={onCancel}>Close</button>
</form>
);
}
// file: feedbackPopup.tsx
function FeedbackPopUp() {
const [isModalOpen, setIsModalOpen] = useState(false);
const openModal = () => setIsModalOpen(true);
const closeModal = () => setIsModalOpen(false);
return (
<>
<button onClick={openModal}>Provide feedback</button>
<Modal title='Provide your valuable feedback' isOpen={isModalOpen} close={closeModal}>
<FeedbackForm onCancel={closeModal} onSubmit={closeModal} />
</Modal>
</>
);
}
render(FeedbackPopUp);
What is good about this design?
- The modal component doesn't care about anything other than being a modal. It only needs to do one thing properly, that is being a modal, how to properly render the modal, how to close it, the styles for the modal, and so on. The modal will be opened by the parent, but it'll be closed by the modal itself, so it takes a close function as arg.
- FeedbackForm component only deals with handling the form, cleaning it up and calling the submit function with necessary form input values. This component does not need to know where it will be rendered, whether to open/close the wrapping modal and so on.
- In order to use this modal component in other use cases, the modal itself should not need to be changed at all.
- Lastly the feedbackPopUpFeature combines the modal and form components to produce the desired feature. You can even take it one step further and create all the inputs as separate components.
- Just like the modal and feedbackForm components all the react components should be individually reusable. They should not be tightly coupled at all. So that we can always mix and match multiple components together to produce new features.
While doing the above, do not define nested components
Inside the function components, we have the ability to define more function components, but the problem is, whenever the outer component re-renders, the inner components will be re-defined triggering more-renders of the inner components. We'll discuss more about gotchas while working with function components in a bit
Split the code into small pieces as much as possible, so that each piece becomes independent. Your feature should be simply a configuration file that configures all the pieces of code to work together as per the requirement. If the requirements change, you change the configurations. Not the underlying pieces of code.