Skip to content

What is RxJS? And Why You Should Know About It

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

There are a lot of interesting tools and resources to pick and choose from in this vast world of frontend development. In an effort to curate a powerful and practical direction with my learning, I sat down with one of the most prominent figures in the RxJS community, Ben Lesh, to learn more about RxJS and why it would be a good investment of time, as a junior developer, to learn and incorporate it into my code.

He walked me through ways I can apply RxJS and tips on how to go about learning it.

Q: What is the problem that RxJS solves?

A: Coding is all about problem solving and finding the right tools to fix the right problems. In the case of RxJS, the problem being solved is the ability to handle asynchronous calls with multiple events. But what does that mean exactly?

Imagine that you are writing a function that carries data along a series of actions and there is an error. If you are just using functions to handle the series of requests, there may be some unnecessary steps that are taken to return the error. Rather than passing the error through all of the functions, it should be able to take the error and update the view without running through the now unnecessary Ajax requests.

You may note that promises are made to solve this type of error handling, but RxJS takes the concept of funneling consecutive actions to the next level. A promise can only handle a single value, limiting it use cases. Additionally, promises are not cancellable, meaning that it has the potential to block the thread and use up unnecessary resources (important consideration for resource constrained devices).

Conversely, RxJS offers a solution to these limitations by offering more than one channel of communication to simplify the handling of a multi-step event in an efficient way. RxJS also provides developers the ability to treat anything that needs to fire an event as a single shaped thing. When everything is the same shape, it becomes very easy to combine and merge and query those things resulting in a very powerful tool.

Q: Why learn RxJS?

A: On the upside, it is a powerful tool that turns complicated series of actions into concise code that is easy to manipulate. On the downside, there is a lot of language involved that requires a bit of time to learn. However, it is worth it when you realize that with one line of code, you can do something like build a drag and drop which takes three sets of events and coordinates them together (mouse down, mouse movement, mouse up) to make one concise line of code. Which would otherwise be a few dozen lines of code.

Q: What are the perks of using RxJS?

A: One of the most attractive features of integrating RxJS into your code base is that the more you use it, the more you can do with it. RxJS is analogous to using Legos in the sense that Legos are great for inventive construction because all the nobs are the same shape. Similarly, all observables take the same form so building with observables becomes an enticing proposition because you can entertain many creative solutions. The more one uses observables throughout a code base, the more options you have to build upon existing structures.

Q: What would it look like if one wanted to integrate observables into a large codebase?

A: You can use observables in pretty much any application. It might take a bit of time to adjust as a team but if you:

-Start with applications of observables that are simple and appropriate -Comment the action well -Are willing to work with your team to educate everyone on what you are doing

It should be a smooth and helpful step for your team. It might take some time for everyone to learn it on their own, but don’t be surprised if you see your team start to “Rx everything”. When actions use observables, they all take the same shape and it becomes more exciting to use as it becomes more ubiquitous throughout your app.

Q: Is it ever not a good idea to use observables?

A: Sure! If it’s a single event and it’s doing a single thing, like a lot of JavaScript programming is, then RxJS is a little silly -– you can use it, but it would be overkill.

A drag and drop is a perfect example of when you would use it. It is an event with multiple actions that call for a reduction in complexity when possible.

Q: How can you tell when you should use Observables?

A: It is helpful to qualify when to use observables by context. For example, -If your action triggering multiple events — use RxJS -If you have a lot of asynchrony and you are trying to compose it together — use RxJS -If you run into situations where you want to update something reactively — use RxJS -If you are handling huge sets of data in arrays and you need to process the sets of data in steps, you can use RxJS operators as a sort of transducer where it processes those sets of data without creating intermediate arrays that then need to be garbage collected later.

Q: Where should one start when diving into the plentiful world of Rx operators?

A: Your go-to list of operators should include map, filter, and scan. Other important operators would be: -switchMap -concat -share / shareReplay

You can narrow your use of operators to less than 10 most frequently needed operators. There are always the strange esoteric operators to play around with like pairwise, bufferCount and groupBuy. They exist for a reason, but you don’t use them very often. However, on the occasion that you do need to perform these functions, you don’t have to go through the headache of building it yourself.

Q: How easy is it to get started writing RxJS in a framework like React? A: It is very similar to implement RxJS in React as it is to implement in Angular where is has been fully adopted. In Angular, observables are first class citizens so there is a particular ease that comes with using it in Angular. However, it is as simple as subscribing to RxJS on ComponentDidMount and unsubscribing on ComponentWillUnmount. It is the same idea as when you implement in Angular if you were to implement it manually.

Q: Do you have any tips on debugging Rx?

A: Like anything, it becomes easier to debug as one learns more about it and becomes more comfortable using it. There are some situations that are difficult to debug. I’m currently working with the Chrome dev team to work out solution for these particular cases.

One common obstacle people run into is when you return something from a mergeMap and its expecting an observable, but it returns something that is not an observable, people want to be able to see the function that is returning what they thought was an observable but is not. Currently, there is no way to show that because you can’t know the form of what is being returned until after it has returned. The pro-tip for this case is to: -use a lot of console log -compose the do operator into the observable chain so that you can see where the observable is in each step and what is being returned.

Q: What is coming up in the Rx future?

A: There are a few changes to look forward to in the future of RxJS. Lettable operators will soon be introduced for public use. Instead of having operators where you have a map operator on an observable itself, you’ll be given a map function and when you call it, it returns another function that an observable will then use to do the exact same work. For example, rather than writing observable.map.filter.scan, you write observable.compose(map, filter, scan). This is a very powerful change because when you get functions building functions a lot of functional programming opportunities opens up. Another advantage associated with this change will be better tree shaking. Right now that isn’t happening with RxJS because everything is being stuck on a prototype so you can do the dot chaining. So it assumes your using it all even though you are not.

Q: How is the growing popularity of RxJS changing the landscape of React and Angular?

A: As RxJS becomes more accessible and easier to integrate, I hope it will become more ubiquitous throughout the frontend community. Currently the two biggest obstacles to using RxJS are the learning curve and the space it takes up. RxJS has been around for a long time but previously the core team found it very difficult to figure out how to get it into the hands of the programmer in an understandable way. The creators of Rx are brilliant but they use complicated terminology which has resulted in a lack of participation by the average developer. Thanks to an increased advocacy for learning resources such as This Dot, there has been a large uptick in developer adoption of this remarkable tool.

To further the ease of this adoption, I am currently working on reducing the size of the RxJS. You can look forward to news of Tiny Rx — or T-Rx which takes the 24k (g-zipped) library to just 3k!

It is very exciting to see the growing popularity and implementation of Rx across the community. While interest has increased, there is still a way to go before it becomes widely used in communities outside the valley. It will be interesting to be a part of this growth and development of such a powerful tool.

Now that you have dipped your toes into the possibilities provided by RxJS, if you are interested to learn more, check out more resources like Rx Workshop, Intro to Rx, Thinking Reactively, RxJs in Depth.

Interviewee Ben Lesh Software Engineer at Google RxJS 5+ Project Lead

Author Necoline Hubner React Apprentice at This Dot @necolinesan

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

Using Custom Async Validators in Angular Reactive Forms cover image

Using Custom Async Validators in Angular Reactive Forms

What is a validator in Angular? First, let's talk about Validators. What is a validator, and how we can use them to improve our forms. Ocasionally, we want to validate some input in our fields before submission, which will be validated against an asynchronous source. For instance, you may want to check if a label or some data exists before submission. In Angular, you can do this using Async Validators. Create a basic application We are going to create a very minimalist form that does one thing: check if the username already exists. In this case, we are going to use a mix of async and sync validators to accomplish our task. It's very common, in most registration forms, to require an unique username. Using an API call, we to capture if that username is already in use according to the database. ` Created a basic form that has a FormGroup called registrationForm, with 2 FormControl. Also, I added 2 sync validators for make the input required and also to check if the input has a minimum length, using Validators.required and Validators.minLength in each case. ` I'm using @angular/material just to simplify our styles, and because it provides a clean way to display errors using the mat-error component. This component will be shown to the user if the required error is present. The button also checks if the FormGroup is valid, otherwise it will be disabled. Async validators Our current app works pretty well, and in most cases, will meet all of the requirements. But what if we want to make sure that the username is unique before allowing the user to submit their information?. Creating an Async Validator could be simple. Let's find how to create it, and add it to our current form. ` Our method to check if the username already exists is called checkIfUsernameExists. It returns an observable with a 5 seconds delay to simulate a very slow API call. Now, we can create our Async Validator to check if the username exists against that method. ` Our UsernameValidator class takes our UserService as an argument. This method returns a AsyncValidatorFn which receives the FormControl that is placed on, providing us access to the current value. An AsyncValidatorFn must return either a promise or an Observable of type ValidationErrors. We use the RxJS map operator to check the value emitted, and either return null if the user doesn't exist, or return a ValidationError with an error type of usernameAlreadyExists. ` We import our UsernameValidator and UserService into our component, and declare in the constructor component. The UsernameValidator is added to our FormControl as the third parameter, calling the createValidator method, and passing a reference to the UserService. ` We update our template to check for an additional error called usernameAlreadyExists, so if our UserService finds that the username already exists, it will provide a to the user based on her status. > The validation status of the control. There are four possible validation status values: > > VALID: This control has passed all validation checks. > > INVALID: This control has failed at least one validation check. > > PENDING: This control is in the midst of conducting a validation check. > > DISABLED: This control is exempt from validation checks Let's see StackBlitz in action. Conclusion Creating beautiful forms for our web app might seem simple, but it's typically more complicated than one would expect. Sometimes, we also need to verify the information, because we don't want to blindly send data to the backend, and then reject it. This can lead to a poor experience for users and result in low adoption rates. Creating an AsyncValidator can help us improve the user-experience, and also avoid sending data to the backend, resulting in a rejection....

How to Contribute to RxJS cover image

How to Contribute to RxJS

This Dot Media is kicking off a brand new series of videos in 2022 to help developers learn how they can contribute code to some of the world’s most popular JavaScript frameworks and technologies. Subscribe to This Dot Media’s Youtube Channel. To continue our series, highlighting best practices for developers interested in contributing to their favorite technologies, I met up with my good friend and creator of RxJS, Ben Lesh. If you would like to check out that interview, you can see it here. What is RxJS? RxJS is a library for reactive programming that uses Observables to make it easier to compose asynchronous or callback-based code. It is a rewrite of Reactive-Extensions/RxJS with better performance, better modularity, better debuggable call stacks, all while staying mostly backwards compatible, with some breaking changes that reduce the API surface. Ben Lesh Ben Lesh is an international speaker and RxJS Core Team Member. His involvement with the framework started a few years ago, when he was asked to work on a rewrite due to his open-source experience in other projects at Netflix. What to Know Before You Get Started According to Ben, the codeofconduct.md and contributing.md documents are the best places for new developers to start. It is crucial that new contributors abide by community standards and the correct commit format, so be sure to read through! *Quick Tips!* -Everything in RxJS is written under src/internal, where you can look at all the internals of RxJS. -The commit message generates the changelog, which can be found on changelog.md. The Best Way to Get Started When I asked Ben what areas of the repository were best for new contributors, and what areas needed the most attention, he of course said: documentation. But it’s true! According to Ben, devs can simply click the “Improve Documentation” button, and do a direct commit. Presently, the team could significantly benefit from contributors interested in checking links to ensure that they are not broken, revising grammatical errors, ensuring all information is up to date, and adding edit buttons in the documentation for individual pages. However, if developers are looking for a different challenge, they can see open requests for contribution by checking out the “help wanted” tag in the issues section. *Quick Tips!* -Don’t simply submit a bunch of PRs to get on the contributors list! Focus on contributing helpful, meaningful work that will advance RxJS! -Because issues are not checked every day, you want to make sure that there is not already a PR for it, and that it hasn’t already been assigned to someone. Also, make sure to look through the PRs to ensure that the issue is not being addressed in both open and closed PRs. What About Attending Core Team Meetings? Core Team meetings typically address in-depth issues and questions related to RxJS, and are not open to the public. However, contributors can receive invitations based on their PRs and need, so if developers are interested in attending Core Team meetings, the best thing to do is create a presence in the RxJS Community! Though meetings aren’t open or recorded, community members can view the issues, and see the tag “agenda item” to see what topics will be addressed at upcoming meetings. Usually, the discussions are commented on in the issues. *Quick Tips!* -If you are interested in getting involved, but don’t want to contribute code, go out into the world and review external articles or Stack Overflow, and help in the community! -Blog posts and explanations about RxJS are also valued by the community and Core Team! Ready to Begin? You can find the RxJS repository here!...

What Sets the Best Autonomous Coding Agents Apart? cover image

What Sets the Best Autonomous Coding Agents Apart?

Must-have Features of Coding Agents Autonomous coding agents are no longer experimental, they are becoming an integral part of modern development workflows, redefining how software is built and maintained. As models become more capable, agents have become easier to produce, leading to an explosion of options with varying depth and utility. Drawing insights from our experience using many agents, let's delve into the features that you'll absolutely want to get the best results. 1. Customizable System Prompts Custom agent modes, or roles, allow engineers to tailor the outputs to the desired results of their task. For instance, an agent can be set to operate in a "planning mode" focused on outlining development steps and gathering requirements, a "coding mode" optimized for generating and testing code, or a "documentation mode" emphasizing clarity and completeness of written artifacts. You might start with the off-the-shelf planning prompt, but you'll quickly want your own tailored version. Regardless of which modes are included out of the box, the ability to customize and extend them is critical. Agents must adapt to your unique workflows and prioritize what's important to your project. Without this flexibility, even well-designed defaults can fall short in real-world use. Engineers have preferences, and projects contain existing work. The best agents offer ways to communicate these preferences and decisions effectively. For example, 'pnpm' instead of 'npm' for package management, requiring the agent to seek root causes rather than offer temporary workarounds, or mandating that tests and linting must pass before a task is marked complete. Rules are a layer of control to accomplish this. Rules reinforce technical standards but also shape agent behavior to reflect project priorities and cultural norms. They inform the agent across contexts, think constraints, preferences, or directives that apply regardless of the task. Rules can encode things like style guidelines, risk tolerances, or communication boundaries. By shaping how the agent reasons and responds, rules ensure consistent alignment with desired outcomes. Roo code is an agent that makes great use of custom modes, and rules are ubiquitous across coding agents. These features form a meta-agent framework that allows engineers to construct the most effective agent for their unique project and workflow details. 2. Usage-based Pricing The best agents provide as much relevant information as possible to the model. They give transparency and control over what information is sent. This allows engineers to leverage their knowledge of the project to improve results. Being liberal with relevant information to the models is more expensive however, it also significantly improves results. The pricing model of some agents prioritizes fixed, predictable costs that include model fees. This creates an incentive to minimize the amount of information sent to the model in order to control costs. To get the most out of these tools, you’ve got to get the most out of models, which typically implies usage-based pricing. 3. Autonomous Workflows The way we accomplish work has phases. For example, creating tests and then making them pass, creating diagrams or plans, or reviewing work before submitting PRs. The best agents have mechanisms to facilitate these phases in an autonomous way. For the best results, each phase should have full use of a context window without watering down the main session's context. This should leverage your custom modes, which excel at each phase of your workflow. 4. Working in the Background The best agents are more effective at producing desired results and thus are able to be more autonomous. As agents become more autonomous, the ability to work in the background or work on multiple tasks at once becomes increasingly necessary to unlock their full potential. Agents that leverage local or cloud containers to perform work independently of IDEs or working copies on an engineer's machine further increase their utility. This allows engineers to focus on drafting plans and reviewing proposed changes, ultimately to work toward managing multiple tasks at once, overseeing their agent-powered workflows as if guiding a team. 5. Integrations with your Tools The Model Context Protocol (MCP) serves as a standardized interface, allowing agents to interact with your tools and data sources. The best agents seamlessly integrate with the platforms that engineers rely on, such as Confluence for documentation, Jira for tasks, and GitHub for source control and pull requests. These integrations ensure the agent can participate meaningfully across the full software development lifecycle. 6. Support for Multiple Model Providers Reliance on a single AI provider can be limiting. Top-tier agents support multiple providers, allowing teams to choose the best models for specific tasks. This flexibility enhances performance, the ability to use the latest and greatest, and also safeguards against potential downtimes or vendor-specific issues. Final Thoughts Selecting the right autonomous coding agent is a strategic decision. By prioritizing the features mentioned, technology leaders can adopt agents that can be tuned for their team's success. Tuning agents to projects and teams takes time, as does configuring the plumbing to integrate well with other systems. However, unlocking massive productivity gains is worth the squeeze. Models will become better and better, and the best agents capitalize on these improvements with little to no added effort. Set your organization and teams up to tap into the power of AI-enhanced engineering, and be more effective and more competitive....

Introduction to Vercel’s Flags SDK cover image

Introduction to Vercel’s Flags SDK

Introduction to Vercel’s Flags SDK In this blog, we will dig into Vercel’s Flags SDK. We'll explore how it works, highlight its key capabilities, and discuss best practices to get the most out of it. You'll also understand why you might prefer this tool over other feature flag solutions out there. And, despite its strong integration with Next.js, this SDK isn't limited to just one framework—it's fully compatible with React and SvelteKit. We'll use Next.js for examples, but feel free to follow along with the framework of your choice. Why should I use it? You might wonder, "Why should I care about yet another feature flag library?" Unlike some other solutions, Vercel's Flags SDK offers unique, practical features. It offers simplicity, flexibility, and smart patterns to help you manage feature flags quickly and efficiently. It’s simple Let's start with a basic example: ` This might look simple — and it is! — but it showcases some important features. Notice how easily we can define and call our flag without repeatedly passing context or configuration. Many other SDKs require passing the flag's name and context every single time you check a flag, like this: ` This can become tedious and error-prone, as you might accidentally use different contexts throughout your app. With the Flags SDK, you define everything once upfront, keeping things consistent across your entire application. By "context", I mean the data needed to evaluate the flag, like user details or environment settings. We'll get into more detail shortly. It’s flexible Vercel’s Flags SDK is also flexible. You can integrate it with other popular feature flag providers like LaunchDarkly or Statsig using built-in adapters. And if the provider you want to use isn’t supported yet, you can easily create your own custom adapter. While we'll use Next.js for demonstration, remember that the SDK works just as well with React or SvelteKit. Latency solutions Feature flags require definitions and context evaluations to determine their values — imagine checking conditions like, "Is the user ID equal to 12?" Typically, these evaluations involve fetching necessary information from a server, which can introduce latency. These evaluations happen through two primary functions: identify and decide. The identify function gathers the context needed for evaluation, and this context is then passed as an argument named entities to the decide function. Let's revisit our earlier example to see this clearly: ` You could add a custom evaluation context when reading a feature flag, but it’s not the best practice, and it’s not usually recommended. Using Edge Config When loading our flags, normally, these definitions and evaluation contexts get bootstrapped by making a network request and then opening a web socket listening to changes on the server. The problem is that if you do this in Serverless Functions with a short lifespan, you would need to bootstrap the definitions not just once but multiple times, which could cause latency issues. To handle latency efficiently, especially in short-lived Serverless Functions, you can use Edge Config. Edge Config stores flag definitions at the Edge, allowing super-fast retrieval via Edge Middleware or Serverless Functions, significantly reducing latency. Cookies For more complex contexts requiring network requests, avoid doing these requests directly in Edge Middleware or CDNs, as this can drastically increase latency. Edge Middleware and CDNs are fast because they avoid making network requests to the origin server. Depending on the end user’s location, accessing a distant origin can introduce significant latency. For example, a user in Tokyo might need to connect to a server in the US before the page can load. Instead, a good pattern that the Flags SDK offers us to avoid this is cookies. You could use cookies to store context data. The browser automatically sends cookies with each request in a standard format, providing consistent (no matter if you are in Edge Middleware, App Router or Page Router), low-latency access to evaluation context data: ` You can also encrypt or sign cookies for additional security from the client side. Dedupe Dedupe helps you cache function results to prevent redundant evaluations. If multiple flags rely on a common context method, like checking a user's region, Dedupe ensures the method executes only once per runtime, regardless of how many times it's invoked. Additionally, similar to cookies, the Flags SDK standardizes headers, allowing easy access to them. Let's illustrate this with the following example: ` Server-side patterns for static pages You can use feature flags on the client side, but that will lead to unnecessary loaders/skeletons or layout shifts, which are never that great. Of course, it brings benefits, like static rendering. To maintain static rendering benefits while using server-side flags, the SDK provides a method called precompute. Precompute Precompute lets you decide which page version to display based on feature flags and then we can cache that page to statically render it. You can precompute flag combinations in Middleware or Route Handlers: ` Next, inside a middleware (or route handler), we will precompute these flags and create static pages per each combination of them. ` The user will never notice this because, as we use “rewrite”, they will only see the original URL. Now, on our page, we “invoke” our flags, sending the code from the params: ` By sending our code, we are not really invoking the flag again but getting the value right away. Our middleware is deciding which variation of our pages to display to the user. Finally, after rendering our page, we can enable Incremental Static Regeneration (ISR). ISR allows us to cache the page and serve it statically for subsequent user requests: ` Using precompute is particularly beneficial when enabling ISR for pages that depend on flags whose values cannot be determined at build time. Headers, geo, etc., we can’t know their value at build, so we use precompute() so the Edge can evaluate it on the fly. In these cases, we rely on Middleware to dynamically determine the flag values, generate the HTML content once, and then cache it. At build time, we simply create an initial HTML shell. Generate Permutations If we prefer to generate static pages at build-time instead of runtime, we can use the generatePermutations function from the Flags SDK. This method enables us to pre-generate static pages with different combinations of flags at build time. It's especially useful when the flag values are known beforehand. For example, scenarios involving A/B testing and a marketing site with a single on/off banner flag are ideal use cases. ` ` Conclusion Vercel’s Flags SDK stands out as a powerful yet straightforward solution for managing feature flags efficiently. With its ease of use, remarkable flexibility, and effective patterns for reducing latency, this SDK streamlines the development process and enhances your app’s performance. Whether you're building a Next.js, React, or SvelteKit application, the Flags SDK provides intuitive tools that keep your application consistent, responsive, and maintainable. Give it a try, and see firsthand how it can simplify your feature management workflow!...

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co