amit kumar
Welcome to my Social Blog
2y ago

𝟱 𝗦𝘁𝗲𝗽𝘀 𝗧𝗼 𝗕𝘂𝗶𝗹𝗱 𝗥𝗲𝗮𝗰𝘁 𝗖𝗼𝗺𝗽𝗼𝗻𝗲𝗻𝘁𝘀 𝗟𝗶𝗸𝗲 𝗔 𝗣𝗿𝗼

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.

What will you write today?

Write, publish, get feedback, and become a better writer.

Trusted by 75,000+ writers