My Journey with React
Rookie Mistakes I Made and How to Avoid Them
Hello developers! I am delighted to share my journey in learning React and shed some light on the rookie mistakes I made starting out. React is a JavaScript library that brings efficiency and ease into building user interfaces. However, like any new technology, it comes with its own set of challenges. By sharing my mistakes, I hope to help you avoid them and make your journey with React smoother and more enjoyable.
- Understanding the Basics of JavaScript:
When I first dived into React, I underestimated the importance of having a strong foundation in JavaScript. React heavily relies on JavaScript concepts so taking the time to understand JavaScript fundamentals is crucial. Make sure you feel confident with topics like variables, functions, arrays, objects, and ES6 features before jumping into React.
- Breaking Components Down into Smaller Pieces:
One of the key principles of React is building reusable components. However, I fell into the trap of creating large, monolithic components that were hard to manage and maintain. Remember to break down your components into smaller, reusable pieces. This not only enhances code reusability but also improves maintainability in the long run.
- Managing State Effectively:
State management is a powerful feature in React, but it can be overwhelming for beginners. I made the mistake of either overusing state or using it for things that should have been derived from props. It’s essential to understand when to use state and when to rely on props or other techniques like context or Redux. Properly managing state will lead to more predictable and manageable code.
// Incorrect: Modifying state directly
import React, { useState } from "react";
function Counter() {
const count = 0;
const increment = () => {
count = count + 1;
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
// Correct way of using State
// State will be updated correctly and the component will be
// re-rendered
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
- Using Keys Correctly:
Rendering lists in React requires assigning a unique key prop to each item. Unfortunately, I overlooked this requirement initially, resulting in issues with component re-rendering and performance. Remember to assign a unique key to each item in a list to help React efficiently manage and update components.
import React, { useState } from "react";
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: "Learn React" },
{ id: 2, text: "Build a project" },
{ id: 3, text: "Deploy to production" },
]);
const deleteTodo = (id) => {
const updatedTodos = todos.filter((todo) => todo.id !== id);
setTodos(updatedTodos);
};
return (
<div>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
{todo.text}
<button onClick={() => deleteTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
/*
Assigning a unique key to each item in the list is important
because it helps React efficiently manage and update components.
When an item is added, removed, or rearranged in the list,
React uses the key to identify which specific items have changed.
This way, it can perform targeted updates instead of re-rendering
the entire list, resulting in better performance.
*/
- Embracing Component Lifecycle Methods:
React provides lifecycle methods that allow you to perform actions at specific stages of a component’s lifecycle. I initially ignored these methods or used them incorrectly, missing out on their powerful capabilities. Take the time to understand the lifecycle methods and leverage them to handle component initialization, updates, and cleanup effectively.
In React, the component lifecycle methods have evolved with the introduction of React Hooks. The traditional lifecycle methods, such as componentDidMount
, componentDidUpdate
, and componentWillUnmount
, have been replaced by the useEffect Hook.
- Avoiding Direct State Mutation:
One mistake I made was attempting to modify state directly by directly manipulating arrays or object properties. React’s state should always be updated immutably to ensure data consistency. Instead of directly mutating state, use methods like concat
, slice
, or the spread operator to update state immutably.
// Incorrect Practice
import React, { useState } from "react";
function TodoList() {
const [todos, setTodos] = useState([]);
const addTodo = () => {
const newTodo = {
id: todos.length + 1,
text: "New Todo",
};
todos.push(newTodo); // Directly manipulating the array
setTodos(todos); // Updating state with the same reference
};
return (
<div>
<button onClick={addTodo}>Add Todo</button>
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
</div>
);
}
// Correct practice
import React, { useState } from "react";
function TodoList() {
const [todos, setTodos] = useState([]);
const addTodo = () => {
const newTodo = {
id: todos.length + 1,
text: "New Todo",
};
const updatedTodos = [...todos, newTodo]; // Creating a new array
setTodos(updatedTodos); // Updating state with the new array
};
return (
<div>
<button onClick={addTodo}>Add Todo</button>
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
</div>
);
}
- Organizing Your Code and File Structure:
Proper organization and file structure are vital for a maintainable React application. I learned this the hard way when I ended up with a tangled mess of components in a single file. Take the time to organize your code into separate components and files, making it easier to locate and manage specific functionalities. A well-organized file structure promotes clarity and saves time in the long run. The image below is an example and is in no way perfect.
- Error Handling Matters:
Error handling is often overlooked, but it’s a crucial aspect of building robust React applications. I failed to implement proper error boundaries or handle errors effectively, resulting in crashes and a poor user experience. Learn about error handling mechanisms such as try-catch
blocks and error boundaries to prevent crashes and provide a better user experience.
//The code to be executed is in the try{} block
// catch{} determines how the error should be handled
const fetchData = async () => {
try {
const response = await fetch(countriesUrl);
const data = await response.json();
setCountries(data);
} catch (error) {
console.log('Error fetching data:', error);
}
};
- Utilizing React DevTools:
React DevTools is a fantastic browser extension that provides debugging and profiling capabilities for React applications. Unfortunately, I was unaware of its existence or didn’t use it to its full potential. Don’t make the same mistake! You may consider installing React DevTools and leverage its powerful features to inspect component hierarchies, track state changes, and analyze performance bottlenecks.
- Embracing Unidirectional Data Flow:
React follows a unidirectional data flow, where data is passed down from parent components to child components through props. I often found myself prop drilling or bypassing this proper data flow, resulting in tangled and hard-to-maintain code. Embrace the unidirectional data flow pattern, as it leads to cleaner and more manageable code.
Remember, data can never flow horizontally- in React.
- Routing in React:
Routing in React enhances the unidirectional data flow by providing a way to navigate between different components or pages in a React application. It allows you to define different routes for different components, and when a route is activated, the corresponding component is rendered. I will address routing in a future article.
Conclusion
Embarking on the journey with React is an exciting and rewarding experience, but it’s important to be aware of the common mistakes that beginners, including myself, often make. By understanding and avoiding these pitfalls, you’ll save yourself time and frustration, and build better React applications. Remember, learning from mistakes is part of the process, so don’t get discouraged. Happy coding and may your React journey be filled with success and growth!