Building a React Counter App

ยท

5 min read

Building a React Counter App

Hey there! ๐Ÿ‘‹

I recently wrapped up an exciting project for my AltSchool examโ€”a Counter App. It's a React-based web application, simple in concept but a fantastic way to dive deep into the React ecosystem

Getting Started

To start the project, I jumped into Figma to draft out a simple UI for my counter app with buttons to manipulate the counter and an input field to set a custom value. In less than an hour, I was done with UI (agba designer doings ๐Ÿ‘ฉโ€๐ŸŽจ)

Once I was done with the UI, I went on to set up my React environment create-react-app which is like a magic wand for bootstrapping a React project. Then, I organized my project into components and pages, separating concerns to make the code clean and manageable. See image below๐Ÿ‘‡

project file image

Implementing the Counter Functionality

Custom Hook: useCounter

React's state management was central to my app. So, I introduced a custom hook, useCounter to manage the counter's state. This hook utilizes React's useState to manage the count and provide functions for incrementing, decrementing, and resetting the count. The use of a custom hook here is crucial for encapsulating counter logic and making it reusable across components.

function useCounter(defaultValue = 0) {
  ...
}

Home Component

In home.jsx, I implemented the primary interface for the counter application. The Home component utilizes useCounter to provide the counter functionality. The component includes buttons for incrementing, decrementing, and resetting the count, as well as an input field for setting a specific count.

A critical aspect here was handling user input. I used parseInt to convert the input string into an integer. This function is crucial for ensuring that the input is correctly interpreted as a number.

const submitCount = () => {
  const numericValue = parseInt(input, 10);
  if (!isNaN(numericValue)) {
    setValue(numericValue);
  }
};

React Router

For navigation, React Router (react-router-dom) was implemented. It allowed me to define routes for different components, such as the home page and a custom 404 error page.

<Route path="/" element={<Home />} />
<Route path="*" element={<PageNotFound />} />

Page not found(404 error handling)

For handling non-existent routes, I created a PageNotFound component. This component displays a friendly message and an option to navigate back to the home page, enhancing user experience in case of navigation to an undefined route.

Error Boundary

Implementing an error boundary was one of the challenges. I created an ErrorBoundaryTest component to catch and handle errors in any child components. This feature is essential for enhancing the app's reliability, preventing the entire app from crashing due to an error in a single component.

function CounterLayout({ children }) {
  return (
    <ErrorBoundaryTest>
      {children}
    </ErrorBoundaryTest>
  );
}

Styling with CSS

The styling was done using CSS, focusing on a user-friendly and visually appealing interface. I used CSS Flexbox for layout design, ensuring responsiveness and a clean layout. The styling was complemented by importing custom fonts for aesthetic enhancement.

Challenges & Solutions

Implementing Error Handling

Setting up navigation to the error boundary page was a challenge. In React, an error boundary is a component that catches JavaScript errors anywhere in the child component tree, logs those errors, and displays a fallback UI instead of the component tree that crashed. The fallback UI I created was to display something like "Oops! Something went wrong" with a helpful note to any user on the next steps, but the UI was not rendering on the front-end. I had to integrate a link in the Home component to intentionally trigger an error. This was done using a component, ErrorTrigger which simply throws an error when it's rendered. Additionally, I used a piece of state, showErrorTrigger to control the rendering of the ErrorTrigger component.

Here's the code snippet from home.jsx:

// Component that throws an error
const ErrorTrigger = () => {
  throw new Error('Intentional Error');
};

const Home = () => {
  // State to control the rendering of the ErrorTrigger component
  const [showErrorTrigger, setShowErrorTrigger] = useState(false);

  // ... other code ...

  return (
    <div className='counter_main'>
      // ... other code ...

      {/* Link to trigger the error */}
      <div className='error_entry-points'>
        <Link to="/" onClick={() => setShowErrorTrigger(true)}  className='error_entry-points_links'>
          Trigger Error
        </Link>
      </div>

      {/* Conditionally render the ErrorTrigger component */}
      {showErrorTrigger && <ErrorTrigger />}
    </div>
  );
};

Ensuring a User-friendly Interface:

I wanted the app to be intuitive. So, I took extra care with button placements and feedback messages. Testing different layouts and button sizes, I found the sweet spot for a seamless user experience.

Styling:

CSS can be wild sometimes. To keep it under control, I used modular CSS, separating styles according to components. This way, I avoided conflicts and could easily maintain the styles.

Ensuring that the application was responsive across different devices required meticulous CSS styling. I used media queries to adjust the layout and font sizes according to the screen size, ensuring a consistent user experience on desktops, tablets, and smartphones.

Wrapping Up

In the end, the Counter App turned out to be a robust little application that I'm proud of. It's not just about counting numbers; it's about creating a pleasant experience for users while brushing up on my React skills.

I can't wait to take on more projects like this. Each line of code is a step forward in my journey as a developer, and every challenge is an opportunity to learn.

It's not real until it's live, right? I deployed the app on Vercel for the world to see. Check it out here. It's quite the charmer! Happy coding! ๐Ÿ˜„