Designing React Components for Reusability and Efficiency
Tags: react, javascript, reactnative
Published: 2023-11-09 11:26:05

This is about how I thought of ways to make taking care of all project on me easier.

When creating components, we usually encounter two distinct types:

**Reusable components** are built to be resuable across multiple parts of an application.

**Non-Reusable components** are tailored for a particular use case.


Now, let's learn how to build these components and spot some common slip-ups.

## Reusable components
Here's a simple button component:

```javascript
const Button = ({ color, text, onClick, size }) => {
  const styles = {
    backgroundColor: color || 'white',
    padding: size === 'large' ? '16px 32px' : '8px 16px',
    fontSize: size === 'large' ? '18px' : '14px',
  };

  return (
    <button
      style={styles}
      onClick={onClick}
    >
      {text}
    </button>
  );
};
```

You can use this component into your project right away.

it is important to design reusable components so that anyone can use them even if they are distributed as open source.

But sometimes we make them non-reusable like this:

```javascript
const Button = ({ color, text, size }) => {
  const dispatch = useDispatch();
  const isLoggedIn = useSelector(state => state.user.isLoggedIn);

  const styles = {
    backgroundColor: color || 'white',
    padding: size === 'large' ? '16px 32px' : '8px 16px',
    fontSize: size === 'large' ? '18px' : '14px',
  };


  return (
    <button
      style={styles}
      onClick={handleClick}
      disabled={!isLoggedIn}
    >
      {text}
    </button>
  );
};
```

In this component, you can see it relies on Redux. This means we can't easily use this button in a different project. It's not reusable anymore.

## Non-Reusable components
Often, we need to create non-reusable components.

I'm taking a closer look at a common pattern many of us follow Here's to-do list.

```javascript
import React, { useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { addTodo, toggleTodo } from '@/actions'; 

const TodoList = () => {
  const [task, setTask] = useState('');
  const todos = useSelector(state => state.todos);
  const dispatch = useDispatch();

  const handleAddTodo = () => {
    if (task) {
      dispatch(addTodo(task));
      setTask('');
    }
  };

  const handleToggleTodo = (index) => {
    dispatch(toggleTodo(index));
  };

  return (
    <div>
      <h1>Todo List</h1>
      <input
        type="text"
        value={task}
        onChange={(e) => setTask(e.target.value)}
      />
      <button onClick={handleAddTodo}>Add</button>
      <ul>
        {todos.map((todo, index) => (
          <li
            key={index}
            onClick={() => handleToggleTodo(index)}
          >
            {todo.text}
          </li>
        ))}
      </ul>
    </div>
  );
};

export default TodoList;
```

This code isn't too long, so you might think it's pretty easy to work with. But if you've ever come across a really long component, you know it can be tough to figure out what's happening.

To prevent complexity, you might want to consider using a custom hook.

Here's how the to-do list looks with a custom hook:

```javascript
import { useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { addTodo, toggleTodo } from './actions';

const useTodos = () => {
  const [task, setTask] = useState('');
  const todos = useSelector(state => state.todos);
  const dispatch = useDispatch();

  const handleAddTodo = () => {
    if (task) {
      dispatch(addTodo(task));
      setTask('');
    }
  };

  const handleToggleTodo = index => {
    dispatch(toggleTodo(index));
  };

  return {
    task,
    todos,
    setTask,
    handleAddTodo,
    handleToggleTodo
  };
};

export default useTodos;
```

You might think that a custom hook can be hard to grasp, but the idea is straightforward: if you want to manage and controll state or side effects, you can organize them all within a custom hook.

And we can make to-do list component like below.
```javascript
import React from 'react';
import useTodos from './useTodos';

const TodoList = () => {
  const {
    task,
    todos,
    setTask,
    handleAddTodo,
    handleToggleTodo
  } = useTodos();

  return (
    <div>
      <h1>Todo List</h1>
      <input
        type="text"
        value={task}
        onChange={(e) => setTask(e.target.value)}
      />
      <button onClick={handleAddTodo}>Add</button>
      <ul>
        {todos.map((todo, index) => (
          <li
            key={index}
            onClick={() => handleToggleTodo(index)}
          >
            {todo.text}
          </li>
        ))}
      </ul>
    </div>
  );
};

export default TodoList;

```

Now, in the to-do list component, there's nothing about state management.
If you need to make changes related to state, you would only need to edit the custom hook file. This approach makes maintenance easier.