Noob v/s expert React developer's code

ยท

4 min read

I was participating in a 30-day challenge on codedamn.com where I came across a problem statement that required me to create a Tabs component. Tabs are a commonly used component in modern applications and websites. They are essentially buttons that display corresponding content below, based on the active Tab.

But how can we develop it using React and what is the difference of noob code and expert's code of same component. Let's get started.

Let's start with noob's code. As a noob developer, we often forget some principles and just want to make things functional . It's good in beginning to get things functional but the solution written is often unmaintainable and may cause problems in later development.

Here's the example noob code for Tab component :-

import styled from "styled-components";
import {useState} from 'react'

const person = {
    name: "John Doe",
    age: 32,
    occupation: "Developer",
};

const address = {
    street: "1234 Main St",
    city: "San Francisco",
    state: "CA",
    zip: "94107",
};

const Tabs = () => {
    const [activeTab, setActiveTab] = useState('Person')
    const handleTabSwitch = (currTab) => {
        setActiveTab(currTab)
    }
    return (
        <Container>
            <TabList>
                <Tab data-testid="person-tab" active={activeTab==='Person'} onClick={() => handleTabSwitch('Person')}>Person</Tab>
                <Tab data-testid="address-tab" active={activeTab==='Address'} onClick={() => handleTabSwitch('Address')}>Address</Tab>
            </TabList>
            <TabContent>
                {    activeTab === 'Person' ? 
                    (<PersonContainer data-testid="person-container">
                        <p>Name: {person.name}</p>
                        <p>Age: {person.age}</p>
                        <p>Occupation: {person.occupation}</p>
                    </PersonContainer>) :
                    (
                        <AddressContainer data-testid="address-container">
                            <p>Street: {address.street}</p>
                            <p>City: {address.city}</p>
                            <p>State: {address.state}</p>
                            <p>Zip: {address.zip}</p>
                        </AddressContainer>
                    )
                }
            </TabContent>
        </Container>
    );
};

export default Tabs;

const Container = styled.div`
    width: 400px;
    height: 200px;
    display: flex;
    flex-direction: column;
`;

const TabList = styled.ul`
    display: flex;
    list-style: none;
    margin: 0;
    padding: 0;
    border-bottom: 1px solid lightgray;
`;

const Tab = styled.li`
    padding: 10px 20px;
    cursor: pointer;
    font-weight: bold;
    color: ${(props) => (props.active ? "black" : "gray")};
    background-color: ${(props) => (props.active ? "lightgray" : "white")};
`;

const TabContent = styled.div`
    padding: 20px;
`;

const PersonContainer = styled.div`
    display: flex;
    flex-direction: column;
`;

const AddressContainer = styled.div`
    display: flex;
    flex-direction: column;
`;

The above solution is fully functional and but let's analyze it more deeply where it lacks.

  1. First of all, two different objects are created for each tab and respective tab content.

  2. Initial useState is set as hardcoded string

  3. Ternary operators are used to render the corresponding tab's content.

All these above-mentioned code practice will fail, in case we want upscale this tab component to show more than 2 component. How do we render the corresponding tab content for let's say 5 Tabs. In that either we need to use 5 if-else different conditions which will make the code quality quite bad. Also maintaining the state and make conditional styling on active Tab would be difficult .

So let's move to expert solution and how can we make the above code more readable, maintainable and following DRY (Don't repeat yourself) principle.

As a expert, we will try to render everything dynamically , reducing the repetitive code and conditions and making our code component scalable.

import styled from "styled-components";
import { useState } from 'react';

const tabsContent = {
  Person: {
    name: "John Doe",
    age: 32,
    occupation: "Developer",
  },
  Address: {
    street: "1234 Main St",
    city: "San Francisco",
    state: "CA",
    zip: "94107",
  },
};

const tabs = Object.keys(tabsContent);

const Tabs = () => {
  const [activeTab, setActiveTab] = useState(tabs[0]);

  const handleTabSwitch = (tab) => {
    setActiveTab(tab);
  };

  return (
    <Container>
      <TabList>
        {tabs.map((tab) => (
          <Tab
            key={tab}
            data-testid={`${tab.toLowerCase()}-tab`}
            active={activeTab === tab}
            onClick={() => handleTabSwitch(tab)}
          >
            {tab}
          </Tab>
        ))}
      </TabList>
      <TabContent>
        {Object.entries(tabsContent[activeTab]).map(([key, value]) => (
          <TabInfo key={key} data-testid={`${activeTab.toLowerCase()}-${key.toLowerCase()}`}>
            <p>{key.charAt(0).toUpperCase() + key.slice(1)}: {value}</p>
          </TabInfo>
        ))}
      </TabContent>
    </Container>
  );
};

const Container = styled.div`
  width: 400px;
  height: 200px;
  display: flex;
  flex-direction: column;
`;

const TabList = styled.ul`
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  border-bottom: 1px solid lightgray;
`;

const Tab = styled.li`
  padding: 10px 20px;
  cursor: pointer;
  font-weight: bold;
  color: ${(props) => (props.active ? "black" : "gray")};
  background-color: ${(props) => (props.active ? "lightgray" : "white")};
`;

const TabContent = styled.div`
  padding: 20px;
`;

const TabInfo = styled.div`
  margin-bottom: 8px;
`;

export default Tabs

So here we are rendering the tabs dynamically by mapping to tabContent keys. So it all depends on tabContent object now. We can add as many information in tabContent to show as many tabs we want. For the entries in corresponding tabContent, we mapping over to the current activeTab properties by using Object.entries and rendering the each property dynamically . To show the properties in capitalize , I did some processing using key.charAt(0).toUpperCase() + key.slice(1) . So it the expert solution which is rendering the elements dynamically reducing the repetition and make this code more maintainable.

You can try this problem on your own in local setup or at https://codedamn.com/problem/Omdz6rIRKQJTxCvwj3pwx?challengeList=30-days-of-react.

Thanks for reading ๐Ÿ™Œ

Did you find this article valuable?

Support Prabhjot Kaur by becoming a sponsor. Any amount is appreciated!

ย