Problem
Where can you encounter this problem?
Starter Code
The starter code for this series is here.
After you clone the repo, navigate into the project directory, install the dependencies and start the app:
This is a common problem in many codebases. The problem is essentially the tight coupling of the UI and business logic.
Here is the file with the problem:
This was indeed a real problem one of our community members encountered. We replicated the issue for a larger audience.
Depending on your experience, you might find several problems here. Here are the problems we found:
1. Conditional Rendering
- The check for
!profile || isLoading
is a common pattern. However, it currently renders the same loading message for both conditions, potentially missing a distinct state for an empty profile (e.g., if the API returns no data after loading). - Although conditional rendering is necessary to display different UI elements, the amount of code within the conditional blocks can make the component difficult to read.
2. useEffect
React's useEffect
is one of the deadliest hooks for a codebase in our
opinion. It should be avoided whenever possible. From our experience, a
significant percentage of bugs are caused by useEffect
.
- The
useEffect
here is necessary for fetching initial data (in this case, from our fake API). However, it should still be abstracted out of the component as it adds business logic directly to the UI component.
3. Missing state and state updates that can go out of sync
- The
formData
state can go out of sync with theprofile
state. - The
isLoading
state can go out of sync with theprofile
state. - There is no
error
state. - These issues are quite common when working with API calls and data fetching.
4. Bad Fake APIs
- The fake API implementation is simplistic and does not accurately represent a real API.
setTimeout
can also result in memory leaks if not handled properly (e.g., if the component unmounts before the timeout completes, a cleanup function would be needed).- When real APIs are introduced, this simplistic mock can lead to increased frontend development and testing time because the mock didn't accurately reflect API behavior.
So, what are the solutions?
In the next few chapters, we will refactor the code using some of the best practices to make it more maintainable.
We will try our best to keep the chapters short and simple, but refactoring always involves a lot of going back and forth.
Roughly speaking, we will:
- Separate out the UI from the business logic.
- Bring in Mock Service Worker (MSW) for mocking API calls.
- Use React Query for fetching and mutating data.
We recommend you attempt the refactoring yourself before reading the next chapter. Then come back and read the next chapters to learn more.
Last updated on