amit kumar
4y ago
Welcome to my Social Blog
๐ฑ ๐ฆ๐๐ฒ๐ฝ๐ ๐ง๐ผ ๐๐๐ถ๐น๐ฑ ๐ฅ๐ฒ๐ฎ๐ฐ๐ ๐๐ผ๐บ๐ฝ๐ผ๐ป๐ฒ๐ป๐๐ ๐๐ถ๐ธ๐ฒ ๐ ๐ฃ๐ฟ๐ผ
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.