Incrementally Adopt Modern React Patterns in a Legacy Codebase

Rate this content
Bookmark

In this workshop, we’ll look at some of the approaches and techniques that can be applied when making refactors or adding new features to a legacy React codebase to bring it inline with the latest approaches. We’ll cover topics such as how to use React Hooks to share component logic in a way that will allow reuse in class components; how to incrementally introduce other patterns to a React Redux app; and how to build in flexible UI components via abstractions where we are tied to some global CSS or a component library. Along the way, we’ll touch on many React patterns and state management approaches with the ultimate aim of being able to evaluate these options and let our requirements drive the architecture in moving towards a more robust and maintainable codebase.

This workshop has been presented at React Summit Remote Edition 2021, check out the latest edition of this React Conference.

FAQ

Redux addresses the issue of state being stored in different components, which can be difficult to manage and reason about as an application grows. By introducing a global state managed in a central store, Redux makes it easier to manage and share state across various components without excessive prop drilling.

Redux works with React through the use of higher-order components, specifically the 'connect' function. This function takes a component as an argument and returns a new component that has access to the Redux store. A top-level 'Provider' component is also used to make the Redux store available to the entire application via React's context API.

Alternatives to Redux for managing global state in modern React applications include using React's built-in context API combined with hooks like 'useReducer' and 'useContext'. Additionally, libraries like Apollo Client for GraphQL APIs provide built-in state management solutions that can act as a global store.

You should consider using React's context API when you need to broadcast a state change to multiple nested components. This is especially useful for global states like themes, user authentication, or any other state that needs to be accessible at various levels of the component tree without excessive prop drilling.

A common use case for the React context API is theming, such as implementing a light mode and dark mode. In this scenario, you need to broadcast the current theme to multiple components in the application, making the context API a suitable solution.

To refactor a React class component to use hooks, you first convert the class component into a functional component. Then, replace state management methods like 'this.state' and 'this.setState' with the 'useState' hook, and lifecycle methods like 'componentDidMount' and 'componentDidUpdate' with the 'useEffect' hook.

Hooks in React simplify code by allowing you to use state and other React features without writing a class. They help avoid wrapper hell, reduce the complexity of large components, and align with React's functional programming approach. Hooks also make it easier to share stateful logic between components.

The 'useEffect' hook in React allows you to perform side effects in functional components. It serves the purpose of lifecycle methods like 'componentDidMount', 'componentDidUpdate', and 'componentWillUnmount' in class components, enabling you to run code in response to changes in state or props.

To implement a custom hook in React that uses context, first create a context using 'React.createContext()'. Then, create a context provider component that uses the 'useState' or 'useReducer' hook to manage state and pass this state to the provider's value prop. Finally, create a custom hook that uses the 'useContext' hook to access and return the context value.

If you encounter the error 'useContext must be used within a Provider', it means that the component using the 'useContext' hook is not wrapped in the corresponding context provider. To resolve this, ensure that your component tree includes the context provider at a higher level so that all components needing the context can access it.

Richard Moss
Richard Moss
130 min
09 Jun, 2021

Comments

Sign in or register to post your comment.
Video Summary and Transcription
This workshop focuses on incrementally adopting modern React patterns in a legacy codebase. It covers topics such as building reusable component logic hooks, refactoring legacy code to use hooks, and using context with hooks. The importance of refactoring class components to functional components and using hooks whenever possible is emphasized. The workshop also explores the use of Redux for centralized state management and the use of context for global state. Troubleshooting and error handling are discussed, and the workshop provides exercises for hands-on practice.

1. Introduction to the Workshop

Short description:

Welcome everyone to this workshop about incrementally adopting modern React patterns in a legacy codebase. I'm a software engineering coach and currently a principal engineer at Sainsburys. I've worked on various projects and have experience in training developers. Let's get started.

I guess I was just gonna ask quickly. I guess everyone's in the Discord channel. You can probably see my screen now, hopefully. That's where I'm gonna sort of post all the stuff. If you want to, yeah, feel free to clone and run the installs on the repo now, just save time later. I mean, there will be time, but, you know, it always takes a couple of minutes. But, yeah, I guess we can just start, actually, because it's 5 past, I think. Hopefully more or less everyone's joined. But, yeah, well, let me just present this. And, yeah, if you can't see what I'm presenting or talking about, feel free to just shout out. Like, if you can't see on my screen, or the code or any of those things, just let me know, I'm going to present it in full screen. I don't have two monitors now, I can't tell exactly. But, anyway, welcome everyone to this workshop about incrementally adopting modern React patterns in a legacy codebase. Yeah, you might be wondering who am I quickly, thanks for everyone's introducing themselves as well, that's really nice. Who am I? Software engineering coach, currently principal engineer at Sainsburys. For those of you that have visited the UK, you probably know Sainsbury's, big supermarket. Yeah, I've worked on lots of different things, I've been lead developer on several projects, at leen.js, my previous place where I was a partner. I've done plenty of training as well. I work with React, Kurl Academy, I was the organiser of the boot camps we were running in Portugal and London a couple of years ago. And we did sort of like trainings for developers from all sorts of places. Cool. Let me see if I can go to the next slide. Okay. Cool.

2. Introduction to React Patterns and Hooks

Short description:

Welcome to the workshop on incrementally adopting modern React patterns in a legacy codebase. We will cover building reusable component logic hooks, refactoring and simplifying a legacy React Redux app, and using context with React hooks. We will also discuss the evolution of React patterns, from functional stateless components to the need for class components and the introduction of hooks. Let's explore the circumstances where class components or hooks are needed. Managing state and lifecycle methods were the primary reasons for using class components in the past, but now we have Hooks alternatives for most cases. It's important to keep components as functional components whenever possible. Let's dive into the evolution of React patterns and how we can share component logic.

Welcome everyone to this workshop about incrementally adopting modern React patterns in a legacy codebase. I'm a software engineering coach and currently a principal engineer at Sainsburys. I've worked on various projects and have experience in training developers. Let's get started.

What are we going to see today? This is a bit of an agenda about the idea, the big idea of this talk is how can I improve my legacy React codebase. I'm sure everyone on the call has probably been there. You get onto a new codebase because it's a new job or just when you haven't worked on before at work and there's a bit of legacy code around. There's a lot of different trade-offs when it comes to making different refactors and how to modernise things, and really the ones that you choose, I think, should depend on your objectives. It's always really good, saying this at work, we should let our requirements drive the architecture, and so, yes, we have to think a bit carefully about some of those trade-offs but we will go into some of that in a second. What are we going to see during this workshop? We will see how to build some reusable component logic hooks and how we go about applying that inside class-based components, so how you can incrementally move towards those using hooks and keep using that logic. We will also chat a bit about refactoring and simplifying a legacy React Redux app, starting with what is the point of Redux, what are some of the things that have come in to give us more options, let's say, and how could we think about managing that, and also we will chat about context because it feeds nicely into that, and how we can use context with React hooks for when we want to manage a piece of global state, or I put global in italics because you need to broadcast to components across the tree. Those are the main things we will be having a look at in this session. So, yes, let's get into it. Oh, and then up front a couple of things as well. There will be a couple of breaks. What we will do is I will try to keep the parts of the presentation down to about 30 or so minutes, probably, and then we will do some exercises within that code base inside the breakout rooms, and I will do a little live coding, show you around the exercises, we will do that, and then there will be a couple of ten-minute breaks in between as well because this session is going to go on for some time. For the presentation part, I guess it might be easier if we just do questions at the end, but I promise I will try not to speak for more than 20 or 30 minutes in any one go without stopping. Let's get into it. Let's talk about hooks and why this sort of came about. I think it is important to understand a little bit about the history of how we got here and things, and then we can rationalise about this stuff in a better way. The whole that this was introduced in React was in versions below 16.8 there wasn't a stateful primitive and I'm sure everyone here remembers class components, which led to several big problems. This wrapper hell which you can see on the right-hand side, we will talk more about that, but this is the idea you had to keep wrapping stuff in order to get in the dependencies more than you needed, because components were really just getting stuff from the outside via props for 95% of the time anyway. It also led to really big components and when things get large, they don't get they're hard to read and they're hard to reason about and I think that should always be like one of our KPIs, readability because it goes to maintainability as well. It wasn't very good. Also, it turns out that classes are confusing for both people and computers. There were a lot of things when we were using this class syntax and bear in mind classes in JavaScript are syntactic sugar. That isn't how it works under the hood, right? But it's confusing with this key word and you've got this class property syntax which you could use, but only if your babels configure correctly and all of that type of thing. So that's the people part and it turns out for computers, as well, when it comes to minifying, it didn't quite minify as well. So it was tricky for that and it actually way sort of went against the spirit of the library, I guess, because when it was first conceived, it was conceived with a sort of functional approach in mind, but the class syntax was needed in order to introduce things like the life cycle method. That's why we ended up with it. There was an idea that it would go away at some point, which is all of the reasons why hooks has kind of come about. Cool. So I guess a question for all of you, like what are the circumstances that we needed to use a class component or now like need to use hooks? Can you kind of think of like two, like in what circumstance you need to do that instead of just using functional components? Anybody want to have a crack at that one? At least, I'm sorry go ahead. Sorry, one thing I can think of is for ErrorBoundaries still needing the classes for that. That's true. Yeah, good one. Definitely still need it for the ErrorBoundaries actually, yeah. But like why specifically do we need it for the ErrorBoundaries? What is it about the, there's something here that was applicable in the past as well that you use in ErrorBoundaries that is why you would have to use the class. Oh, okay. That thing, that part I can't remember. How about to manage state? Yes, exactly. That is one of the things very good. Exactly managing state, right? We always had to use the class components to manage state previously. And obviously, now we need to use the use state hook. Yeah, very good. That's one of them. And the other one, we almost got there with the ErrorBoundary, but it's basically life cycle methods. Because actually that ErrorBoundary, that component, the cache, that is a life cycle method. You need to be in a class to use a life cycle method. But basically, for most of them, except the component that cache, we have Hooks alternatives now. But essentially, it's those two cases. This question is a really interesting one to ask yourself. Because I used to see this a lot with code bases and developers, where people would be building class components and not really need to do so. It's always err on the side of like keep your components as functional components and not be like, keep your components as a component. Now, I think stateless components are a really good choice. And as I said before, we're talking about functional components. They used to be called functional stateless components, right? But obviously, that's not a very good name for them anymore, because obviously, they can have state. So yeah, functional components. So let's talk a little bit here about the evolution of React patterns. So as many of you are probably aware, if you've been working with React for a while, well, and even up to date, we still use this one. And we're still using React as a standard programming language. We're still using React.js. We're still using React.js. But now, we're using React.js. And it's a great way to separate our UI and our logic, right? So those presentational components were what we called in the past the functional stateless components. They're just functional components. So they are functions that just render a piece of JSX, right? And they shouldn't really manage any state. They might take, like, a callback or something which was passed down via props, et cetera. So this was a really useful pattern for a long time. And in some cases, we can still try to do that, right, to just separate our concerns a bit. This sort of led to this next pattern that came along, where we said, okay, that's great. We've separated UI and logic. But how can we share component logic? And when I say component logic, I mean these things that we mentioned before, which is like any logic that is associated with lifecycle methods or with stateful logic. In that case, you need to sort of do something else.

Watch more workshops on topic

React Performance Debugging Masterclass
React Summit 2023React Summit 2023
170 min
React Performance Debugging Masterclass
Top Content
Featured WorkshopFree
Ivan Akulov
Ivan Akulov
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
Concurrent Rendering Adventures in React 18
React Advanced 2021React Advanced 2021
132 min
Concurrent Rendering Adventures in React 18
Top Content
Featured WorkshopFree
Maurice de Beijer
Maurice de Beijer
With the release of React 18 we finally get the long awaited concurrent rendering. But how is that going to affect your application? What are the benefits of concurrent rendering in React? What do you need to do to switch to concurrent rendering when you upgrade to React 18? And what if you don’t want or can’t use concurrent rendering yet?

There are some behavior changes you need to be aware of! In this workshop we will cover all of those subjects and more.

Join me with your laptop in this interactive workshop. You will see how easy it is to switch to concurrent rendering in your React application. You will learn all about concurrent rendering, SuspenseList, the startTransition API and more.
React Hooks Tips Only the Pros Know
React Summit Remote Edition 2021React Summit Remote Edition 2021
177 min
React Hooks Tips Only the Pros Know
Top Content
Featured Workshop
Maurice de Beijer
Maurice de Beijer
The addition of the hooks API to React was quite a major change. Before hooks most components had to be class based. Now, with hooks, these are often much simpler functional components. Hooks can be really simple to use. Almost deceptively simple. Because there are still plenty of ways you can mess up with hooks. And it often turns out there are many ways where you can improve your components a better understanding of how each React hook can be used.You will learn all about the pros and cons of the various hooks. You will learn when to use useState() versus useReducer(). We will look at using useContext() efficiently. You will see when to use useLayoutEffect() and when useEffect() is better.
React, TypeScript, and TDD
React Advanced 2021React Advanced 2021
174 min
React, TypeScript, and TDD
Top Content
Featured WorkshopFree
Paul Everitt
Paul Everitt
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
Web3 Workshop - Building Your First Dapp
React Advanced 2021React Advanced 2021
145 min
Web3 Workshop - Building Your First Dapp
Top Content
Featured WorkshopFree
Nader Dabit
Nader Dabit
In this workshop, you'll learn how to build your first full stack dapp on the Ethereum blockchain, reading and writing data to the network, and connecting a front end application to the contract you've deployed. By the end of the workshop, you'll understand how to set up a full stack development environment, run a local node, and interact with any smart contract using React, HardHat, and Ethers.js.
Designing Effective Tests With React Testing Library
React Summit 2023React Summit 2023
151 min
Designing Effective Tests With React Testing Library
Top Content
Featured Workshop
Josh Justice
Josh Justice
React Testing Library is a great framework for React component tests because there are a lot of questions it answers for you, so you don’t need to worry about those questions. But that doesn’t mean testing is easy. There are still a lot of questions you have to figure out for yourself: How many component tests should you write vs end-to-end tests or lower-level unit tests? How can you test a certain line of code that is tricky to test? And what in the world are you supposed to do about that persistent act() warning?
In this three-hour workshop we’ll introduce React Testing Library along with a mental model for how to think about designing your component tests. This mental model will help you see how to test each bit of logic, whether or not to mock dependencies, and will help improve the design of your components. You’ll walk away with the tools, techniques, and principles you need to implement low-cost, high-value component tests.
Table of contents- The different kinds of React application tests, and where component tests fit in- A mental model for thinking about the inputs and outputs of the components you test- Options for selecting DOM elements to verify and interact with them- The value of mocks and why they shouldn’t be avoided- The challenges with asynchrony in RTL tests and how to handle them
Prerequisites- Familiarity with building applications with React- Basic experience writing automated tests with Jest or another unit testing framework- You do not need any experience with React Testing Library- Machine setup: Node LTS, Yarn

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

A Guide to React Rendering Behavior
React Advanced 2022React Advanced 2022
25 min
A Guide to React Rendering Behavior
Top Content
This transcription provides a brief guide to React rendering behavior. It explains the process of rendering, comparing new and old elements, and the importance of pure rendering without side effects. It also covers topics such as batching and double rendering, optimizing rendering and using context and Redux in React. Overall, it offers valuable insights for developers looking to understand and optimize React rendering.
Building Better Websites with Remix
React Summit Remote Edition 2021React Summit Remote Edition 2021
33 min
Building Better Websites with Remix
Top Content
Remix is a web framework built on React Router that focuses on web fundamentals, accessibility, performance, and flexibility. It delivers real HTML and SEO benefits, and allows for automatic updating of meta tags and styles. It provides features like login functionality, session management, and error handling. Remix is a server-rendered framework that can enhance sites with JavaScript but doesn't require it for basic functionality. It aims to create quality HTML-driven documents and is flexible for use with different web technologies and stacks.
React Compiler - Understanding Idiomatic React (React Forget)
React Advanced 2023React Advanced 2023
33 min
React Compiler - Understanding Idiomatic React (React Forget)
Top Content
Watch video: React Compiler - Understanding Idiomatic React (React Forget)
Joe Savona
Mofei Zhang
2 authors
The Talk discusses React Forget, a compiler built at Meta that aims to optimize client-side React development. It explores the use of memoization to improve performance and the vision of Forget to automatically determine dependencies at build time. Forget is named with an F-word pun and has the potential to optimize server builds and enable dead code elimination. The team plans to make Forget open-source and is focused on ensuring its quality before release.
Using useEffect Effectively
React Advanced 2022React Advanced 2022
30 min
Using useEffect Effectively
Top Content
Today's Talk explores the use of the useEffect hook in React development, covering topics such as fetching data, handling race conditions and cleanup, and optimizing performance. It also discusses the correct use of useEffect in React 18, the distinction between Activity Effects and Action Effects, and the potential misuse of useEffect. The Talk highlights the benefits of using useQuery or SWR for data fetching, the problems with using useEffect for initializing global singletons, and the use of state machines for handling effects. The speaker also recommends exploring the beta React docs and using tools like the stately.ai editor for visualizing state machines.
Routing in React 18 and Beyond
React Summit 2022React Summit 2022
20 min
Routing in React 18 and Beyond
Top Content
Routing in React 18 brings a native app-like user experience and allows applications to transition between different environments. React Router and Next.js have different approaches to routing, with React Router using component-based routing and Next.js using file system-based routing. React server components provide the primitives to address the disadvantages of multipage applications while maintaining the same user experience. Improving navigation and routing in React involves including loading UI, pre-rendering parts of the screen, and using server components for more performant experiences. Next.js and Remix are moving towards a converging solution by combining component-based routing with file system routing.
(Easier) Interactive Data Visualization in React
React Advanced 2021React Advanced 2021
27 min
(Easier) Interactive Data Visualization in React
Top Content
This Talk is about interactive data visualization in React using the Plot library. Plot is a high-level library that simplifies the process of visualizing data by providing key concepts and defaults for layout decisions. It can be integrated with React using hooks like useRef and useEffect. Plot allows for customization and supports features like sorting and adding additional marks. The Talk also discusses accessibility concerns, SSR support, and compares Plot to other libraries like D3 and Vega-Lite.