𝟱 𝗦𝘁𝗲𝗽𝘀 𝗧𝗼 𝗕𝘂𝗶𝗹𝗱 𝗥𝗲𝗮𝗰𝘁 𝗖𝗼𝗺𝗽𝗼𝗻𝗲𝗻𝘁𝘀 𝗟𝗶𝗸𝗲 𝗔 𝗣𝗿𝗼
A component is a fundamental building block in React. In this article, we are going to look at a quick way to build truly maintainable, flexible, simple, and reusable components.
Building truly maintainable, and flexible components allow you to make your components future-proof. Software is changed very often as changes in requirements. If you don't write resilient components, it will become a pain to integrate new changes quickly and easily.
Unfortunately, building components that are not maintainable leads to nothing but pain and frustration for both the maintainer and user of the component.
Here are some biggest mistakes leading to nothing pain and frustration when maintaining components.
Building complex components
Adding multiple responsibilities to single components
Building components coupled with several moving parts
Adding business logic in components
Learning this quick technique will not only allow you to build highly maintainable components in React. It will also allow you to make them more resilient and future-proof.
Here's how to step by step:
The pattern we are going to use for building react components is called compound components.
The compound component pattern has been used in the most popular react libraries. The reason for its popularity is that it allows you to build highly flexible components in react.
A simple example of compound component can be seen in HTML is <select> and <option> elements.
A simple example of this pattern is:
<Toggle onToggle={on => console.log(on)}>
<ToggleOn>The button is on</ToggleOn>
<ToggleOff>The button is off</ToggleOff>
<ToggleButton />
</Toggle>
Now, the first step is to create a parent component that will provide API, data, and states common to its children. To share states and APIs from this component to all children under it, we can use react context.
Let's create a simple Toggle component that will display a message depending on its toggle state.
import * as React from 'react';
const ToggleContext = React.createContext();
function useEffectOnMount(cb, dependencies) {
const ref = React.useRef(true);
React.useEffect(() => {
if (!ref.current) {
return cb();
}
ref.current = false;
}, dependencies);
}
function Toggle(props) {
const [on, setOn] = React.useState(false)
const toggle = React.useCallback(() => setOn(oldOn => !oldOn), [])
useEffectOnMount(() => {
props.onToggle(on)
}, [on]);
const value = React.useMemo(() => ({on, toggle}), [on])
return (
<ToggleContext.Provider value={value}>
{props.children}
</ToggleContext.Provider>
);
}
This guard hook will allow you to prevent using the child components outside the parent context.
function useToggleContext() {
const context = React.useContext(ToggleContext);
if (!context) {
throw new Error(
'This component cannot be used outside Toggle',
);
}
return context;
}
Now you can build child components for the parent Toggle component. One thing to keep in mind is that these child components can be used directly inside the toggle. It simply means that you can pass their props directly to them. No need to add them to the parent component. It will allow keeping the parent and child decoupled from each other.
The concept here is that the parent component should not be aware of what the child component consists of.
function ToggleOn({children}) {
const {on} = useToggleContext();
return on ? children : null;
}
function ToggleOff({children}) {
const {on} = useToggleContext();
return on ? null : children;
}
function ToggleButton(props) {
const {on, toggle} = useToggleContext();
return <Switch on={on} onClick={toggle} {...props} />;
}
function App() {
return (
<Toggle onToggle={on => console.log(on)}>
<ToggleOn>The button is on</ToggleOn>
<ToggleOff>The button is off</ToggleOff>
<ToggleButton />
</Toggle>
)
}
There is a toggle status label added above ToggleButton. This component is so flexible that you can add/remove any part in the Toggle app without having to change anything in the Toggle component.
An important thing to remember here is that this pattern must be used in cases when your component has multiple moving parts (children). Do not use it with atomic components like: Button, Input where there are no multiple moving parts.
0
Thread