So, after a good chunk of time tinkering with different setups in my projects and steering the ship at work, I stumbled onto something pretty cool. I call it the "boring" React way. it's been the secret sauce for the stuff I've led at my job. Everyone's been pretty darn happy with it. So, grab a seat, and let me share my "boring" way and I would love to debate about it.
Embrace React Query
Embrace the boring brilliance of React Query.
React Query handles all the data logistics you hate: automatic caching, background updates, and error handling.
Once you try it, you will never choose to do anything manually for data fetching.
const { isLoading, error, data } = useQuery('todos', fetchTodoList);
if (isLoading) return <div>Loading todos...</div>;
if (error) return <div>Error fetching todos: {error.message}</div>;
return (
<ul>
{data.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
)
That's it! No more complex state management or useEffect
hooks. React Query handles everything, leaving you with a clean and concise way to fetch and manage data in your components.
So why is it “boring”? because it is so stable, so reliable, with tons of features that have a lot of use cases, you will rest your head and forget about all the data fetching the problems
And for you, that means more time for centering that div.
Component Development: Take It Step by Step
Build Components as You Go
I don’t believe in “design components first, then starting the project”. design as you build, refine as you go.
Start with Simple Components:
Focus on core functionality and behavior.
Create components that solve specific problems within a feature.
Don't worry about perfect styling or visual polish at this stage.
function FeatureXCard({ data }) {
return (
<div className="feature-x-card">
<h2>{data.title}</h2>
<p>{data.description}</p>
<button onClick={() => handleAction(data)}>Action</button>
</div>
);
}
Iterate Based on Feedback and Usage:
Gather feedback from users and collaborators (PM/QA etc).
Observe how components are used in context.
Refine UI, interactions, and overall user experience.
Identify common patterns and reusable elements (This is why you should definitely use Storybook)
Promote Reuse and Independence:
Extract components that have proven their value and versatility.
Make them more generic and adaptable to different contexts.
Move them into a shared library or component collection.
// Your Library componenet
function Card({ title, description, action }) {
return (
<div className="card">
<h2>{title}</h2>
<p>{description}</p>
{action && <button onClick={action}>Action</button>}
</div>
);
}
// Reusing the component in Feature X
function FeatureXCard({ data }) {
return <Card {...data} action={() => handleAction(data)} />;
}
// Using the component in other features
function FeatureYCard({ data }) {
return <Card {...data} />;
}
Skip the design silo, start with features! Prioritizing features first in React development puts users at the center, letting components evolve naturally within context. This leads to adaptable, collaborative, and ultimately, better applications (I’ve seen a lot of projects with tons of “zombie” and “lonely” components just sitting there in their storybook).
EVERYTHING is Configurable
Centralizing Config for Control and Clarity
Everything is configurable – and it all lives in config
.
Think of it as your application's control panel. Tweak data fetching timeouts, customize components, and even adjust global settings – all from this central HQ. It's not just about order; it's about flexibility.
Fine-tune individual features, maintain app-wide consistency and collaborate with ease.
const fetchTodoList = async () => {
const response = await fetch(`${AppConfig.api.baseUrl}/todos`, {
timeout: AppConfig.api.timeout,
});
};
With configuration as the only source of truth in its folder, your codebase stays clean, your team stays aligned, and your masterpiece shines brighter than ever.
Formik & Yup: The Epic Duo
Forms. Ugh. Built-in validation,State management,Error messages and handling the submit actions. But fear not, Formik & Yup are going to save the day.
Formik: magically handling state, validation, and submission. No more manual tracking, complex logic, or error message.
Yup: The Regex patterns? It parries them. Custom messages? It writes them. Field dependencies? It controls them. No invalid data
Together, they're an unstoppable:
const SignupForm = () => {
const validationSchema = Yup.object({
email: Yup.string().email('Invalid email format').required('Required'),
password: Yup.string().min(8, 'Must be at least 8 characters').required('Required'),
});
return (
<Formik
initialValues={{ email: '', password: '' }}
validationSchema={validationSchema}
onSubmit={(values) => {
// Handle form submission here
}}
>
{({ errors, touched }) => (
<Form>
<Field type="email" name="email" placeholder="Email" />
{errors.email && touched.email ? <div>{errors.email}</div> : null}
<Field type="password" name="password" placeholder="Password" />
{errors.password && touched.password ? <div>{errors.password}</div> : null}
<button type="submit">Sign Up</button>
</Form>
)}
</Formik>
);
};
Encapsulation over freedom
Encapsulation is not a constraint but a framework for harnessing the creative freedom.
It involves encapsulating componenets & layouts within well-defined boundaries.
This is what encapsulation contributes to your project:
1. Predictability: Encapsulation establishes clear interfaces and modular boundaries, allowing developers to predict how changes in one part of the code may impact others. (And Easier testing!)
2. Maintainability: As projects evolve, maintenance becomes crucial. Encapsulation encourages the creation of self-contained modules with well-defined interfaces, facilitating localized updates and bug fixes.
3. Building the "Boring" Project for Lasting Success: Encapsulation, by emphasizing a robust design, contributes to creating a dependable project that stands the test of time.
4. Balancing Freedom within Boundaries: Encapsulation is not about imposing restrictions but providing a disciplined structure. It offers developers the freedom to innovate within well-defined modules.
Conclusion : It does matter for YOU.
Users (and most non technincal PMs) are not going to judge the project based on how you write code but on the user experience (UX). Therefore, it is crucial to research and apply some good UX practices, .
Additionally, incorporating lazy loading for routes is essential for optimizing performance, ensuring a smooth user experience, and reducing initial page load times. By addressing these aspects, the "boring" React approach can not only provide stability but also deliver a delightful and efficient user experience.
Thanks for reading !
Well done!