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:
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:
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.
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:
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.
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.
Top comments (1)
This post is really helpful. When the projects starts to get bigger and complex, reusing components and differenciating the non-reusing ones is essencial. Thank you for the insight!