A Love Letter to Gen Z from Gen Y: Understanding React's Evolution

anishamalde

Anisha Malde

Posted on April 9, 2024

A Love Letter to Gen Z from Gen Y: Understanding React's Evolution

Now, before I get cancelled, let me explain 😅 I'm on the cusp of the boundary between Gen Y and Gen Z and I learnt React during the class component era. However, my stint with class components was only 2 years, which coincidentally is also the number of years between myself and the official cutoff of Gen Y. This made me think that - most of Gen Z would likely have learnt React from a point of functional components & hooks!

Consider this letter my reflections on the generational divide between the "Class Component Generation" and the "New Gen of React Devs," along with unsolicited coding tips for bridging that gap. And so really, the inclusive title is:

“A Love Letter to the New Gen of React Devs from the Class Component Gen of React Devs”

My Dearest Gen Z / New Gen of React devs,

Whether from the bustling virtual classrooms of coding bootcamps to turning caffeine into code during late night coding sessions, we've both embarked upon our own unique journeys to learning React.

Your’s began with functional components, where as for us, it was with class components.

Functional vs Class Components

When hooks stole our heart’s

Heart Stolen

In 2019, with the release of Hooks in React 16.8, the way we all learned React changed significantly. Prior to hooks, functional components were largely used for simple, stateless rendering, while class components handled the more complex logic, state management, and lifecycle methods. However, with the introduction of hooks, functional components gained the ability to manage state and side effects and it altered the way React applications were built.

Justifiably, the hooks docs assumed the reader was familiar with class components. However, those learning React post-2018 likely didn't prioritise learning class components, as the React ecosystem was shifting towards a functional component approach, leaving little incentive to learn the "old way." This caused some:

Unintended Differences (but, Differences make the heart grow fonder)

Differences

As a result of your learning journey, there are some notable "generational differences", highlighted in the quotes below, in your approach to React development compared to ours. Let us explain each difference and how it came to be:

1. “Your generation didn’t learn the life cycle methods”

Explanation: This is the most significant difference. For us, the class components generation, managing state meant we were forced to understand the nuances of the lifecycle methods (componentDidMount(), componentDidUpdate(), and componentWillUnmount()). These methods provided clear entry points for initialising, updating, and cleaning up state, that hooks abstracted away.

2. “Your generation tend to jump to state management libraries”

Explanation: Prior to hooks, integrating Redux into a React application was a PAIN. It required a good understanding of the flux architecture and oh-so-much boilerplate code. So even though, with hooks, the process of integrating Redux (or rather Redux Toolkit) has become much easier, the scars of past serve as a reminder of the potential complexities making us less likely to reach for a state management library.

3. “Your generation doesn’t like using TypeScript”

Explanation: Class components provided an object-oriented programming (OOP) approach to React, which aligns well with the typed nature of TypeScript. Consequently, we are more inclined to TypeScript as a means of enforcing code maintainability and improving the type safety that was lost when we switched to functional components.

4. “Your generation love using hooks”

Explanation: Class components had specific lifecycle methods like shouldComponentUpdate that allowed for manual control over component re-rendering, encouraging developers to think about performance optimisation. With hooks like useCallback and useMemo, the optimisation techniques are not as explicit or intuitive, making it harder to identify the most effective use of these hooks. Similarly, because class components required a deeper understanding of the component lifecycle and how it relates to rendering and updating we were able to understand when to touch the DOM when using useRef().

5. “Your generation take testing for granted”

Explanation: (this one is probably my most opinionated) The step-by-step nature of class components encouraged testing practices, as we had to address each component's lifecycle events and behaviours individually. Additionally, class components required more explicit setup for testing, such as mocking lifecycle methods. Comparatively, testing functional components is much “easier” now, so for us its a “no brainer”, while for you it may seem like an afterthought.

So I guess what i’m trying to say is, we may have been too quick to judge your coding choices and a little too harsh in our code reviews. But upon reflection, it's clear that our different learning journeys have shaped our approach to React development. And just as we wouldn't expect you to understand our love for flip phones and skinny jeans, it's unfair to expect you to have the same understanding of class components and lifecycle methods.

So now, instead of dwelling on our differences, let's focus on how we can bridge the gap and learn from each other.

Instead of criticism, allow us to offer: React Love Advice

Advice

Dont carry unneccessary baggage: Avoid storing unneeded state (“Your generation didn’t learn the life cycle methods”)

  • We learned the hard way, that unnecessary state can quickly lead to complexity and performance issues. Avoid storing state that can be calculated from other state values, prop values, or isn't essential.
  • Enforce Immutability, don't transform data in state – transform that data while rendering instead
  • Watch out for duplicated or deeply nested state.

Master the love language of hooks! (“Your generation love using hooks”)

  • Managing the component lifecycle explicitly taught us the importance of separating concern. useEffect may seem like a simple way to handle side effects and state updates, however we’ve learned that multiple useEffect calls with many dependencies can quickly lead to spaghetti code and performance issues.
  • On the flip side, watch out for missing dependencies in useEffects as this can lead to unexpected behaviour in your application.
  • Make use of the cleanup function returned by useEffect to avoid memory leaks and properly handle component unmounts.
  • Don't overuse hooks like useMemo and useCallback, as premature optimisation, as this can have the opposite effect to its intended purpose due the the overhead of these hooks
  • Theres a great talk on using hooks: using useEffect Effectively by David Khourshid or 12 useState & useEffect Mistakes Junior React Developers Still Make in 2024. by ByteGrad

TypeScripting our way to a stronger relationship! (“Your generation don’t like using TypeScript”)

  • TypeScript improves type safety, maintainability, and scalability – all crucial as your applications grow!
  • Many popular libraries and frameworks (e.g. React Native) are now going down the TypeScript as a default route.

Managing Our Love State (Management) (“Your generation jump to state management libraries”)

  • Understand when to use a State Management Library, only reach for Redux or similar libraries when you have a clear use case.
  • At the same time don’t stick everything into one Context, break down your state into smaller, more manageable contexts that are specific to different parts of your application. This is a great article from Kent C Dodds.
  • For managing asynchronous operations, consider a library like TanStack Query.

Nurturing Our Love with Tests (“Your generation take testing for granted”)

  • Keep components focused on a single responsibility. Refactor complex logic into custom hooks or utility functions. A good reference is the book Clean Code by Robert Martin.
  • Make sure your component isn’t too large, coupled or nested and think about the dependency flow.
  • Follow principles like unidirectional data flow, atomic design, and decoupling components.
  • Favour composability over inheritance. I really like this page from the legacy react docs.
  • Post hooks, the project structure of React changed (e.g. no more container). Consider folders for hooks, context, and types and ensure you are thinking about the core principles of readability, maintainability, and reusability from the star. This will save you refactoring headaches down the road.
  • Pass dependencies into a function or component from the outside, rather than having the function or component create or manage its dependencies internally (Dependency Injection).

In the future, we will get through this together

Together

So now as we venture into the unknown world of React 19 with its Server Components and the new React Compiler. We can share notes and ponder together on whether the compiler will ease the pains of useMemo(), useCallback() or if we are going to have to work together to write an article for the post-compiler generation 😉

With all my love,
Gen Y / The Class Component Generation of React Developers

Massive thank-you to Joe Brady, Charlotte Isambart, Justin Zelinsky, Justin Kek, @hellonehha and Antony Clements who fed into the Lessons Learnt

Please drop any comments of other lessons learnt / your experience!

💖 đŸ’Ș 🙅 đŸš©
anishamalde
Anisha Malde

Posted on April 9, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related