The demo has three inputs that represent three different available categories. The user can modify the title of each category. There is a dropdown to choose one of the three available categories. Once a category is chosen, it displays its title and ID.

Demo

NOTE: This demo was built solely for the demonstration of this bug. It is, by no means, a perfect code with best practices

The Bug

Choose a category and modify the title in the input text. You will see that the title in the details of the selected category does NOT change. It still has the previous value.

When you re-select the category, it updates the title.

My team and I built the category-modification-feature only after the dropdown had already been built. It is the careless way in which we added this new feature that caused this bug.

The Duplication

The component has two states: one for the categories list and another with for the selected category:

const [ categories, setCategories ] = useState(initialCategories);

const [ selectedCategory, setSelected ] = useState(initialCategorySelected);

The initialCategorySelected is just a workaround to add a “Select Category” option to the dropdown. You can ignore it.

When the user selects from the dropdown, this happens:

const newSelected = selectableCategories.find((category) => category.id === newSelectedId);

setSelected(newSelected);

As you can see, it passes a whole category object to setSelected . The category object that was selected.

We have two categories objects: one in the categories array, another one in the selectedCategory state. Two objects representing the same thing. THIS IS THE DUPLICATION.

When the user edits a category in the input field, this happens:

const updatedCategories = categories.map((category) => {

if (category.id === updatedCategoryId) {

return {

…category,

title: newCategoryTitle,

}

}

return category;

});

setCategories(updatedCategories);

A new array of categories is created and the title is changed for the category being edited. THIS IS WHEN IT GOES OUT OF SYNC.

There is no code to update the selected category with the new title.

Avoid duplication

How do we avoid duplication?

Simple enough, let’s store the id of the selected category, instead of the whole object:

const [ categories, setCategories ] = useState(initialCategories);

// AVOID DUPLICATION!

// const [ selectedCategory, setSelected ] = useState(initialCategorySelected);

const [ selectedCategoryId, setSelected ] = useState(0);

With the selectedCategoryId we can select the object from the categories array and work with it:

const selectedCategory = selectableCategories.find((category) => category.id === selectedCategoryId);

When the user chooses from the dropdown, store the id instead of the whole category object in the state.

// AVOID DUPLICATION!

// const newSelected = selectableCategories.find((category) => category.id === newSelectedId);

setSelected(newSelectedId);

Conclusion

I hope that by now the conclusion is clear. AVOID DUPLICATION.

Most rules and best practices are there because more experienced developers learned from their mistakes and created shortcuts in the form of rules.

The problems of skipping those rules might not appear immediately. However, they might come in the future to hunt you.

Related Stories