BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Presentations RxJS: A Better Way to Write Front-End Applications

RxJS: A Better Way to Write Front-End Applications

Bookmarks
43:56

Summary

Hannah Howard talks about the premise of functional reactive programming. Data itself is treated as asynchronous - as streams which represent a snapshot, a given value over time, and operations that can transform those values. Functional reactive programming is a major conceptual shift but one that can vastly simplify front-end programming.

Bio

Hannah Howard is a senior developer and tech generalist with over 15 years experience in programming and other technical fields. Currently, she works at Carbon Five.

About the conference

Software is changing the world. QCon empowers software development by facilitating the spread of knowledge and innovation in the developer community. A practitioner-driven conference, QCon is designed for technical team leads, architects, engineering directors, and project managers who influence innovation in their teams.

Transcript

Hi, my name is Hannah [Howard]. Before we start, I'm going do that real quick self intro. If you like this talk and you want to find me on the internet, I usually go by the handle @techgirlwonder, I use she/her pronouns, that's my logo. I've only done one good drawing in my entire life, and I intend to milk that for at least a decade.

I work for a company called Carbon Five. We are a product development agency, we work with all kinds of companies. We take their products basically from conception to completion, and from startups to enterprise. We are both hiring and hireable, so talk to me afterwards if you're into it. And finally, here is my dog, and she's pretty cute, obviously, and she can vouch for me so you know that I'm a nice person or something.

What is a Computer Program?

So this is a talk about reactive programming, and why I believe it is a better way to write frontend applications. It's in five parts. Here we go. Hello to all of the legendary children, and welcome to the functional reactive programming ball. Tonight the category is, "What is a computer program?" So there's a very important computer science textbook that I refer to frequently, and that textbook defines a computer program as "a sequence of instructions for performing a task designed to solve specific problems." The part of this that stands out to me is this phrase, "sequence of instructions." And the reason it stands out is, whenever I think about it, I think of like a to-do list, right? You imagine programming in a very sequential order.

If we were to take this into a different context, like a classroom, you might think of it as a lesson plan for the lesson. “First I'm going to do this, then I'm going to do this, and then I'm going to do this.” But is that really an accurate metaphor? So if you are programming, maybe a command line utility, it's probably pretty accurate, because you're just executing things sequentially. But the context of this talk is frontend programming. And so if you're doing frontend programming, I have a different metaphor that I think applies better.

And that's the unruly classroom, because in frontend programs, they don't run sequentially. There is no sequence. In fact, the flow of execution is constantly interrupted by user input, right? Whether you're talking about user input or you're talking to a server that may or may not be responsive, there's a million other things. And I actually would argue that the central challenge of writing frontend programs is dealing with interruptions.

A Brief History of Interruptions

So to talk about that, let's look at a brief history of how we've dealt with interruptions in the context of frontend programming. So I started programming in the early '90s-ish, and at the time, the very first type of programming I ever did was DOS game programming. You all are going have to bear with me while I do one thing, because I just realized that I did not do one small piece of setup here. Just give me one moment. You know that you're writing your presentations with code when you have to clear local storage in order for your presentation to work. Let's refresh. Thank you all for bearing with, I appreciate it. I was so close to a flawless presentation, but not today. And that's still not there, but whatevs.

So I started programming in C. Now, I don't know how many of you all have ever programmed in C. You don't have to have programmed in C to get this example. Basically, the way it would work is, if you wanted to accept user input, you had this facility whereby you could override something called the BIOS. And the BIOS was this super-duper low level, almost hardware piece of like code, and you could basically jump in the middle and say, every time there's a key tapped on the keyboard, I want to handle it, right? And then your new keyboard, this would be like your new keyboard code, and it would probably do something like collect key presses in some kind of a buffer.

And then your whole program would look like a loop. And the loop, the contents of it, would be, basically you would on each iteration, you would check some kind of input, whether it's keyboard, mouse, joystick, or whatever, and then you would process it and do something with it. So you can imagine a bus of events. And you'd basically do that until you were done. Now, there's one problem with this model, which is, if you wrote a bad piece of code to handle the keyboard handler, like in this case an infinite loop, you've actually taken over the keyboard. So there is no control-C. Your program is running forever, and you're going to have to restart your computer.

Briefly, I did some programming in Windows. And Windows was basically the same model, except it did one innovation, which was they decided to not give regular programmers direct access to the hardware, which was probably a good idea. But if you look at the actual code, it looks pretty similar. You're again just doing this sort of infinite loop, where you take each message, you do something, you try to read it, figure out what it is, and then process it. And then the main code that you would write as a Windows programmer is a program to look at each message, basically decide which type of message it is, and update the state of your application.

So that takes us up to about 1999, when we realized that the global event bus was a limited pattern, and we left it in the dust for better things. Or did we? Because if you look at this code, right, and you look at the core logic of your program being a switch statement that takes a message and then updates the state based on that type of message … How many people here are programming in React, or have programmed in React? All right, so if any of you all are using Redux, this might look a little bit similar, because it's basically a reducer, right? And, in fact, Redux uses a lot of the patterns of the global event bus in its design.

So, while programming in Redux may be programming like it's 1999, there are some good reasons that they went that way, and I'll talk about that in a bit. But, let's move on to what I consider sort of the core pattern of doing UI programming that we've used as, effectively since we moved off of the global event bus, and that's this thing called the observer pattern. And I'm going to explain it in a little bit of detail, because it's really important to understanding the things we're going to talk about in the rest of the talk.

I'm going to do a short digression to explain the observer pattern, and it's into the world of influencers. So, let's say you're an influencer on the internet, and you're a content creator, and you're wondering that very important question, how are people going to see my awesome content, right? So there was an old way of doing it in the pre-internet age, which is you tracked people down and you were like, "You’ve got to check out my thing and watch this." This is when producers would stand out on the street and be like, "Check out my album." But, in the modern age, we have this better model for doing this. If you are a content creator, you essentially say, "I'm going to publish content." And then me as your adoring fan, I go on to one of our wonderful, scary surveillance social media platforms, and I subscribe to your content. And once I've subscribed, when you make content, I will get a notification that you've made new content. And that'll give me the opportunity to watch it.

And this model is effectively what the observer pattern is. You have these two concepts, the subject and the observer. The subject is analogous to the content creator, and the observer is analogous to the fan. And the subject essentially says, "I'm going to produce some kind of event." The observer says, "I want to subscribe to that event." And then whenever that event happens, the observer gets notified and can choose what to do with it. And if you're programming in JavaScript, you've actually probably done this a few times. I'm having a little trouble with this but, yes. So, if you've programmed in JavaScript at almost any point in the web, you've actually implemented this pattern and you may not have known it.

So, in this scenario, we've got two elements on the page. We have a switch, or a button you can click, to toggle the content of another content box. So imagine it's like a light switch, and when you click on it, the goal is to change the text in the other box from on to off, right? So how do you implement this? This piece of code is how we would normally look up a DOM element. In this case, we're looking up the switch, right? And then we've written a function here that when called, essentially flips the text in the other element, the toggle from on to off. So how are we going to connect these two things?

So we have this function that you can call, and this is part of the DOM API, where you can add an event listener to a user event on a DOM element. In this case, we're adding an event listener to the click event on the toggle switch. And by doing that, and then we pass to it a handler, and by doing that, we convert our modifyText function into an observer. So now, essentially, every time I click, the modifyText function is going to get called, and that will trigger, that will cause the switch to change. So this is effectively the observer pattern, and you're using it every day.

So how does this compare to the global event bus? Well, one thing that's great about it is that it's way simpler. You've probably used this pattern a million times without even thinking about it. We wanted to process, we wanted to set up one user interaction, so we set up one observer and one function, and then we were done. It's basically much more localized. You don't have to deal with all the events you don't care about.

The one downside to this is you do have to set up subscriptions. So you do write a little bit of code to subscribe to the events, so that you can subscribe to these different events. And that works really well, but there are certain cases where it gets a little complicated. I don't know if anyone here has ever attempted to implement drag and drop, not with the current browser APIs, but with the old fashioned, mouse down, mouse move, and mouse up. It's pretty complicated, because what you end up doing is you have one handler listening for the mouse down. Once you get the mouse down, you set up another handler to handle the mouse moving, and then meanwhile you have to also have a handler and the mouse up that removes the mouse move handler when it's done. It's like quite a bit of stuff.

The issue here is you're mixing two concerns in your code. On the one hand, you're handling events, but then in complicated user interactions, your event handlers themselves, end up having to handle the task of setting up and tearing down subscriptions. And it gets pretty complicated. So the observer pattern is great, and it's reliable, but it has some downsides. And although this is not an official story, this is my notion of how Redux might have gotten created, because they might have been looking at the observer pattern and being like, "This is actually getting kind of cumbersome. Maybe we should give this global event bus a try." But, maybe there's another way to do this that offers the convenience of the observer pattern, but with the flexibility of the global event bus. And that is what the rest of this talk is about.

Functional Reactive Programming

I want to talk about functional reactive programming, and how you can use it to write frontends like a boss. So I want to go back to our classroom analogy. Once upon a time, I don't know if this was in my bio, but I actually was a middle school teacher. But I was really bad at it. So don't learn from me. I want to look at how good teachers handle that situation, this unruly classroom. So I don't know if you've ever watched a good teacher in action, but they're almost like Jedi. They have this way where like a student is interrupting, and they just sort of like Obi-wan them back into, you want to be, this is the lesson you're looking for. So how do they do that.

Well, the first thing is that teachers don't start with a strict lesson plan. They have a lesson plan, but it's kind of like a guide. Because if you start with a strict plan, and you try to stick to it rigidly, you're going to get interrupted. Instead, you can think of teaching as kind of like a series of semi-planned reactions to different types of interruptions. And really good teachers, if a student does something, they know how to not just respond and bring that student back to the lesson, but to actually take that interruption and kind of fold it into the flow of the lesson in a way that just sort of inevitably flows toward the final objectives that they're trying to get to for the overall lesson. So it is kind of like Jedi mind control. And that's why teachers are actually way more talented workers than most of us. And I think we ought to pay them like we pay us, but, sidebar.

How could we write programs like this? Could we write programs as a series of planned responses to interruptions? What would it look like? Well, so I want you to consider a statement, "Y equals X plus 3." You've probably written something like this somewhere along the line in your history of being a computer programmer, right? And in the imperative context, this means something very specific. It means take the value of X, add three to it, and assign it once to Y. If X later changes, it's kind of like Y still has the value you assigned it.

But let's think about that statement in a different context. In math, Y equals X plus 3 actually describes an entire line on a graph, with the whole slope-intercept function, whatever. So it doesn't just describe one assignment of like Y to X plus 3; it describes an entire possible line you could plot on the graph. And in reactive programming, this statement would express a relationship between Y and X. So X is a value that can change over time, and Y is a value, and essentially this says that Y is a value that will change every time X changes, and it will always have the value X plus 3.

So you can imagine X, let's imagine it as like a stream of values over time. And then, if you imagine it as a stream of values over time, if you were to express the Y stream, it would essentially be another stream of values, where each value emitted was the same, was essentially the value emitted by X, plus 3. And if you think of this concept of a stream of data, it doesn't necessarily have to be actual numbers. It could be anything. It could be a stream of mouse clicks. We could just track every time the user clicks the mouse over time.

So how would you program like this? Well, that seems really cool in theory, but most of us know that at least somewhere under the hood, there's a computer sequentially executing instructions, like the original definition said. So how would we program like this? What we would need is some kind of pattern so that as each value changes over time, we could subscribe to those changes and get notified and then be able to respond. So that pattern is the observer pattern. We just need to add a few things and extend it a little bit. So the observer pattern kind of assumes that we're dealing with some kind of user- sorry, I'm going to go right to the next slide. So, we're going to rewind. What I'm getting at is we're going to introduce this concept called an Observable. An Observable is like a subject, except that it could be, you could observe anything. It's just effectively a stream of any kind of value that changes over time. So how could we program with this? Let's look at how this could work.

So imagine we have an X, and we've said it's a stream of data values, a stream of numbers, that changes over time. If we wanted to print out the values of X, we could just subscribe to it. This would just be the standard observer pattern. And then, we might say, let's say we want to print out the values of Y. Well, we could subscribe to X, and we could just print out whatever was emitted plus 3. And this would give us an output of the values of Y. But what if we wanted to actually listen to Y itself? How would we do that?

So let's step back for a moment and just rewind to something a little more familiar, and imagine X is just an array of numbers, right? In most computer programming languages, if we wanted to calculate Y as the array of numbers that are in Y, based on the array in X, we could use an operation like map. That's usually what most languages call it, but if they don't, they often have some kind of operation like this. So in the Observable case, it basically functions the same, and we're going to use an operator that looks exactly like the operator we would use in the context of an array. The difference here is that this is not all happening at once. This is a map of values over time. So the map happens continuously as an X, the new X value appears, its mapped, and then you get a new Y value from that.

So let's look at this in a UI context. In this case, we have two buttons on the screen and a ball. Just bear with me with the abstractness of this. And you can say that, essentially design this so when you click on each button, the ball goes from one end to the other. So how could we implement this UI interaction with Observables? So let's say that we have- just for the moment, let's imagine we can write an Observable that emits the left button clicks and the right button clicks. So essentially as I click on each side, those Observables emit. Now if we have that map operation, we could transform each of these clicks into an actual semantic event. So I could effectively translate the click into a desired position I want the ball to be in. So you can see it's clicking and then it's being transformed into a right as a desired position. And if we merge these two streams of positions, we actually get the current position of the ball. So that's how we could assemble this UI interaction using Observables.

So let's look at what that looks like in code. Sorry for this little situation. So for the rest of the talk, I'm going to use a really great Observable library called RxJS. And our remaining examples are going to be all in JavaScript, but there are great Rx libraries in actually almost every major programming language, which means you can apply these patterns to UI programming in a native Android context, a native iPhone context, or almost any UI platform. So the first step is to look up the two DOM elements, so this is pretty standard. (Ignore that, cancel. Preview of the rest of the talk.) Now, we need to create two Observable streams of the click events on each button. So the simple thing about this is that RxJS just provides us a function to do this. It's essentially a function called fromEvent that takes a DOM element and an event and produces an Observable stream of those events on that DOM element.

Now, we would use the map operation to convert the fact that those things are occurring to an actual position. Now, this syntax might look a little different, and this is partly because RxJS has specific syntax around this, where it wraps all these operations in this pipe function, but it's essentially the same thing. We're mapping a fact that a click occurred to a desired position. And then finally, RxJS provides a function to merge two streams. So we'd just use this merged stream. We're merging it and then we're adding one more thing, which is we're inserting an initial position. And this produces the desired position of the ball. So that's basically it.

How Do I Actually Use This?

We're probably about 25 minutes in, and you're already on board, you're ready to write every single program that you work on this way. But maybe you need a little bit of guidance on how to do this in the real world. So before I get into this, I am going to return to the slide from Laurie's talk, if any of you all were here before lunch. He showed this graph of all these different technologies that are being used in the React ecosystem. And I saw his talk at a couple conferences ago, and when I saw it, I was like, "Wait a second, what is the green line?" And then I was like, "Wait a second, is that, oh my god, it's RxJS and it is the most popular library in the world. It is more popular than React." So, yes, how did that happen? He said I would explain it. Well, the short answer is that people who write some pretty important libraries are using RxJS. RxJS is in the tool chain of libraries for ESLint, and it's also heavily depended on by the Angular framework. So you combine those two together, you get some massive usage.

Now, this isn't saying that's how you use RxJS, it's just saying that the folks who write a lot of the libraries that you depend on are actually using this as a tool to write their own code. But let's say you want to put Rx in your programs in your own user space code. There's a couple questions you need to answer. One is, how do I actually architect real applications using RxJS? And then the second is how do I integrate this with my current application stack?

So, for this scenario, to explain how you would build a program with RxJS, I want to look at a more real world scenario. And we're going to look at a scenario that you've probably all dealt with, which is a login form. So I have like a really silly login form demo here where I can enter a username and password, I'm probably going to want to provide some feedback if the wrong thing is entered. I may want to disable the Submit button while a login is in progress, because it's probably going to need to go out to a server, and I hope not to have double logins. So, it's a little more complicated functionality here. So how would we implement this with RxJS?

Well, let's start from the thing we've like already seen, which is that we can make UI inputs- I don't know if you all can see that, so that says username, password, and Submit button- and convert them to streams. So I can imagine this username, password just emits every time that I type in a new username and the password, same, this is a super secure password form where you can see what I'm typing. And then whenever I click Submit, I get a submit. So if I have all those, we can convert this into effectively a stream of login attempts. Because what is a login attempt? A login attempt is basically combining the last typed username and password every time that a Submit button is clicked, and sending it off to a server. So I could produce a stream of effectively login attempts.

And so then, from login attempts, I can start build, deriving other things. When the response comes back from the server, I could create a stream of responses. And then once I've got that, I can do a bunch of other stuff. I could derive whether there's a login in progress from the time between when a login attempt occurs and when a login response occurs. Once I have a response, I might need to filter it out into successful logins and error logins. And then once I have those, I can convert them to stuff. The login failure, I might be able to extract a stream of failure messages out of it, and the login success I might extract a user token from. And then we could use that user token to kind of feed into another stream of things that could occur. I might use that user token to actually go get a protected resource. And so I can build this entire pretty complicated logic tree from different combinations of Observables.

So if I submit a bad username and password, you can see that it essentially filters all the way down to a failure message. And if I submit a good username and password, and I'm never sure if I've set this up correctly. QCon and awesome, let's try that, see if that works. So I'm submitting, it was a success. So that becomes a user token, and then I go make another API call to a protected resource, and I get my protected stuff. So what would this actually look like in the codes? You're probably like, “well, that was really cool watching little things move around the screen, but doesn't sound like actual computer code.”

First of all, let's imagine I've just made a fake abstraction of an API here. It has a login endpoint and it has a protected resource endpoint, and we can assume that both of these return promises. Okay. So here are our three user inputs, so in this case, I'm using something slightly different than I was before. I'm not going to get too into this, but there's this concept of a subject, which you would use to assemble a stream from user input. So we have a username, a password, and a Submit button. And we could produce our login attempts by essentially, whenever the Submit button occurs, we attach to it the latest username and password emitted. And there's an operator for this called withLatestFrom.

Once we have that, we could convert that attempt into an API call. If you look at this login attempt code, what I'm doing is on each event, sorry each emission, I'm doing a call to our API and submitting the username and password. Now, an API call, in this case, we've said our API returns a promise. So we don't want a stream of promises because that's not very useful data to us. We want a stream of what actually it resolves to. So there's an operator for this, and that operator, it's little bit oddly named, it's called mergeMap. And what that'll do is it'll take this map function, which produces a promise, and it will convert it all to a stream of the actual unwrapped values when the promise returns.

You can again derive the login in progress by just merging the attempts and the responses mapped to essentially the true or false state. And you obviously want to start with it not being in progress. Getting the login successes is really easy. There's just another operator called filter, which effectively takes a stream and produces a stream where the only values that are emitted are the ones that satisfy some condition. In this case, we're filtering the responses that have status of success, and the failures are basically the same thing.

And then, once we have those, we convert to semantic data. In this case, we're mapping our login failures and pulling out the error message from within the payload returned from the server, and producing a message that we then display on the screen as feedback to the user. You can imagine the user token operates the same way. And then once we have the user token, we can effectively start this process over again. We can take that user token and map it to a new set of API responses. And I've got the order a little bit different, but you're effectively doing the same thing with the mergeAll, where you're converting a stream of promises to a stream of actual data coming back. And that's basically how you can build a pretty complex piece of user interaction functionality and state logic with Observables.

So there is a concept, you've seen me draw these diagrams a couple times with these like emissions from Observables, and it's a way to conceptualize how data propagates through a program that's built with Observables. It's called a signal graph. And in this case, in the case of a signal graph, the signals are emissions from the different Observables, and the graph is how they're all tied together. And that's basically the fundamental architecture pattern for building programs using Observables. Our programs become a series of, effectively, reactive data streams, starting with the first user inputs, which we call primary signals, and then propagating to all of these other derived streams of data, and taken together, those form the signal graph. And where I work, at Carbon Five, we actually build a number of programs with RxJS, and we've developed a practice of maintaining the signal graph as an independent drawing that we kind of keep alongside our code base, that tracks how the logic of our program is developing. And this is taken from a real world application.

Now, if you actually do this, and we've been doing this for a couple years, and we've noticed that there are certain challenges that do come up, you're probably wondering how do I actually test all this? You probably want to make sure your graph doesn't end up having cycles in it, because that could produce a lot of unpredictable results. Although I've glossed over it, there are a few idiosyncrasies in RxJS. If you Google hot and cold Observables, you will learn a lot about that. And as your program grows, one thing that we've found is the graph gets really big, and that drawing gets real complicated. So one thing that we've been struggling with is do we maintain just one, conceive of just one graph, or do we have, imagine there's multiple graphs to handle different features, areas of the program, and if so, how do you connect them?

And finally, the graph diagrams tend to take a lot of time to maintain, which doesn't feel very agile. We're supposed to be valuing, working software over documentation, I don't know if I'm getting my words right there. Anyway, so, but we've been working on it for a couple years, and we've developed a lot of good practices for it. And so recently, I was like, "What if we take all these practices and combine them all into like a library that other people could use?"

So I want to talk briefly about a library that I've written called Signal. And it's basically a library for doing state management in your frontend JavaScript apps using signal graphs. So let's take a look at how it works. Awesome, cool. So the first thing you do when you use Signal is you define a signal graph. And there's a really simple DSL for adding different signals for your graph. You can define primary signals and then you can define derived signals. And I'm going to not get too deep into this DSL, but essentially, you have primary signals, and everything after that is derived signals. And the nice thing about this, I always think of it as a routes file for your frontend application, where you can see all the different things that are going to go into this big piece of logic.

And in terms of actual operations of the derived signals, you define a name, you can see that addDerived, you give a name to the derived signal and then you define a factory function for actually making that signal. And the reason you do this is it's really easy to test. So you can see that I'm making a factory function for login attempts that takes as parameters the Submit button, the username, and password, and then produces the resulting signal. So the nice thing is, this is a pure function. I can open up a test and dependency inject it with mock versions of these signals, and they're pretty easy to test then.

And then once you define your graph, you can use a function called initializeWith to hydrate your graph with state. One of the challenges that we've come up against, is how do you set up the initial state of the program. And then finally, you build your graph, and there's just a function to build the graph. And the nice thing about this is Signal is going to take the definition you've provided, along with all the definitions for how you're going to build your Observables, and it's going to handle all the work of setting all that up for you. It's also going to handle stuff like avoiding cyclic dependencies.

And then once you've defined one graph, if you need to define another graph and connect it, it provides an API for connecting basically two graphs together by connecting a, in this case, it's a primary signal for the top graph with a derived signal from the other graph. Now, you might be wondering what are all those strings, this looks very Angular 1-ish. Well, yes, it is string dependency injection, however, if you are using TypeScript, this is all super-duper locked down. And so you can't type in the wrong thing there. It will complain if your types don't match. So it's actually a really specific system for doing dependency injection, if you're using TypeScript, which is a really awesome language. And stay tuned, because we're talking about that next.

So it is available now. I didn't want to crimp on my favorite messaging app's name, so I put it under a namespace. You can install it at npm install @rxreact/signal. Caveat is, I put out like two weeks ago. So, use at your own risk. Or in production. What could go wrong? One thing I haven't been able to get yet, and this is one of the things I really want to get, is an actual thing that will build automatic graph visualizations. So those visualizations you saw earlier, they are really code, they really do operate based off the user input you give to the form. But I would like to be able to just generate them, though right now, they're hand coded. And I believe it's possible, I just haven't been able to get it there.

All right, finally, integration. So now you want to, you've got an idea of how to write applications, but you're working in a context where you are integrating most likely with a JavaScript framework. So how do I tie all this work into traditional JavaScript framework coding? Well, the good news is if you're using Angular, step one is there is no step one. Angular authors integrated RxJS from the beginning, and there's some interesting tooling around it as well, but it's basically part of the framework. But, as we saw earlier in the last talk, Angular, not the most popular framework.

You're probably wondering about the more popular framework, AKA React. And this is sort of the origin of where I got started. I really want to use my React with my reactive programming, and there hasn't been that much tooling out there for it. So, I work at a consultancy. I can't just basically be like, "I'm going to throw in a bunch of obscure reactive programming tools, and then hand it off to your client dev team." That would be somewhat irresponsible. So I've been wanting to build tooling such that that maybe takes off and then maybe we can get a movement going to do reactive programming with React.

So, the good news is, I have something else for this, and that's where the namespace comes from. All of these tools are under the heading "rxreact" because they are tools to integrate React with RxJS. There are actually a few things out there. This is just one example that I happen to be showing because I'm the person giving the talk and I wrote it, but there are several tools out there and many of them are quite good. So the first tool that I've written is a library called signal-connect. And this is basically, if you are using Signal and you want to connect the outputs of the graph to React components, you can use this function called connect. It looks a lot like Redux.

In this case, you can imagine we have a box; we have the box that's moving around, this is from the previous example, and we want to connect that to the output of the position stream. So we just use this connect function, and we essentially provide it the signal graph we're using, the properties we want to set on the React component, and then the name of the stream we want to use to feed that React component.

We can do the same thing in reverse with our primary signals, where in this case, we're taking our left button, and we're taking the component, which has an onClick handler, and we are passing as a property onClick and using the leftClick primary signal. And this will essentially connect that event handler, so when I call the onClick function, it emits a value on the leftClick stream. And that's basically all there is. And one thing that is really cool about this, it kind of goes off the bottom of the screen, but that entire login form component that you saw is about 12 lines of code to connect that entire, the form, to the signal graph.

Used Car Sales Portion

So this is the last portion of the talk, and it's what I call the used car salesman portion, because I'm going to just cover a few more things that I've written very quickly. And this is also the part where my notes get all sparse. I'm obviously a little bit tired today, because I was just over canvassing in Nevada yesterday. So there's another library. If you're like, "I don't really get the signal graph thing, I'm not really into it. I just want to connect React components to Observables." The original library I wrote was called rxreact/core. And it's a simpler version, and the one nice thing is I've been developing this one for a while, and it's basically just to directly connect; if you have an Observable, in this case, here's our leftClick Observable, and we're directly connecting it to an onClick property on the left button. And it's essentially the same thing but without all of this structure of the signal graph.

Obviously, some of you guys might be into TypeScript. You should totally hang around because the next talk is about TypeScript, continuing the JavaScript track theme of cross-marketing our talks. So stay tuned for Lauren's talk about TypeScript. And the nice thing is, while I've kept all my examples in JavaScript, all of this code is written in TypeScript, because I love TypeScript. It's kind of how I like to write my code.

So there is that. There is also- if you are like, "I really like reducers, because I've been programming in Redux," I've been working on a version of this that uses a reducer model combined with Observables to provide an API for backing your components with state. That's very similar to the ReasonML spec. Anyway, that's another thing. That's going through various revisions. That's not out yet, but it will be. I'll have it out soon. Yes, that's the name of that one, and that's all I have. Vote “Yes” on Prop 10 tomorrow, I'm just going to say that. And thank you all for bearing with me.

 

See more presentations with transcripts

 

Recorded at:

May 23, 2019

BT