Video details

The Worlds Most Expensive React Component | Michael Chan | Reliable Web Summit 2021

React
05.25.2022
English

We need to stop building expensive React components — components that promise the world but are impossible to maintain. Let’s fight the apropcylpse and set aside our prop drills with this prop-osal for a more productive way working in React.
ng-conf is a three-day Angular conference focused on delivering the highest quality training in the Angular JavaScript framework. 1500+ developers from across the globe converge on Salt Lake City, UT every year to attend talks and workshops by the Angular team and community experts.
Join the Angular Community: http://www.ng-conf.org/ Get your ng-conf tickets: https://ti.to/ng-conf Follow Us: https://twitter.com/ngconf Learn More: https://ng-conf-school.teachable
Read More: https://medium.com/ngconf
Hear More: http://theangularshow.com
Follow us on twitter https://twitter.com/ngconf Official Website: https://www.ng-conf.org/

Transcript

Hi, I'm Joe Eames. Thanks for checking out this talk from Reliable Web Summit 2021. Online conferences were great, but it's time to get back in person, see old friends, make new ones, and take your career to the next level. Our parent conference, Ng.com, is back and in person on August 31. Head over to Ngcoff.org to get your ticket and stay tuned for information about Reliable Web Summit 2022. Now, enjoy the talk. Close your eyes. No one can see you. So it's not silly. Envision the most expensive React component you can. Think about everything you've learned about React, JavaScript and CSS. Think about all the blog posts you've read with cautionary tales and the flame wars on Twitter. Fanning into flame community fury about how bad things are, and feel the panic you feel when mentally scanning through all of the code you've ever written for violations of this new custom. Got it? Of course you do. And if you don't, then maybe text a teammate and they can tell you about how you violated these rules. Now, if we were together, I would ask you for a list of things that you thought of when you thought of this component. However, we're not. So I'm going to just list a few things that I have heard repeatedly. So one component is too slow, too many renders or it's inefficient too many paints. Heavy, takes too long to load. Unclear. The design underperforms or it's crusty. It employs antiquated techniques and patterns. It could also be unreliable, riddled with errors. Now, I'm not going to talk about any of these things today. That's not the goal of today's discussion. I really think that performance is fairly well covered by a lot of material in the React community these days. What I want to talk about is something that I call collaborative performance. Now, I haven't actually Googled this, so you might find something totally different online, but this is the way that I describe it. The time that we gain or lose with design decisions or the global side effects of bad design decisions. Now, to be clear, I'm not talking about visual design here. That's a much different talk. I'm honing in on API and component interface design, and I'd like to focus. When we talk about interface design and component API design, it'd be helpful to know what's the anatomy of the world's most expensive component. Now, before we do that, I figure I should introduce myself. I'm Michael Chan. You can call me any part of that. Michael Chan. Chan, Michael, Michael Chan. Anything you like. I go by Fantastica most places on the Internet, and you can call me Fantastic if you feel so inclined. I've been a friend and architect for about four years on a mixed stack of a full product suite, and I've been developing component based design systems for twelve years. I'm the host of a show called React Podcast. I'm part of the new React Working Group and I'm building an awesome community at lunchtime, a community of creators. And you can get there at Chan Dev Discord. Now, the reason I tell you all this is because it's kind of important to know that I've seen a lot of the things that we're going to talk about today. So these transitions that we talked about in component APIs, I've seen this hundreds of times over and over and over again. Now, this is a natural successor to a talk that I gave a few years ago called Hot Garbage Clean Coat is Dead. If you like this talk, you might also enjoy that talk. If you hate this talk, you'll probably try to find YouTube support and ask them to take it down and burn the backups. That talk was about me coming to my sense of belonging in web development and overcoming my sense of imposter syndrome and working with my demons. This talk is realizing that my demons aren't the only ones that need to be combated. Unfortunately, we live in a time where it doesn't matter how good one person is. If the organization sees something a different way and you lack the skills to convince them that change is important, well, we're not going to get very far. So back to it. What's the most expensive react component? OK, so for hunting for react components that are expensive, what are we looking for? Well, in my time doing front end architecture, I have to say the most important qualities that I've learned to identify anything is this idea of solid. Now, I'm not going to go through what solid design principles are, but you can hit this Wikipedia article to find out more about that. I will try to reduce that into like a handful of notions that would apply specifically to react components. First of which is it's close to extension, it's not easily composed with other components. That's a bad thing, encapsulating the wrong things. It owns too much and does too little or provides too little value. Third might be that it requires modification to be customized. So you can't really do a lot with it unless you actually modify the underlying code that powers the component. So it's not adaptable. Fourth is it directs folks to use unsuccessful patterns or it's misleading. And finally, it can't be recomposed from smaller parts, meaning it's too rigid. So what behemoth component could achieve all of these terrors? What component could be costing hundreds of thousands of dollars at every single company? What component could be so pervasive that it infects the minds and practices of developers community wide? Well, are you ready? Because you're not going to believe it. I think it's this simple example, the first example on the front page of Reactjs.org. You don't have to take my word for it because I know that this is probably a shocker to you. So I'm going to prove it to you with a little bit of code transformation. So let's get to it. Here we have the world's most expensive react component. I've made two files for this. I've made a single file with an export for this component, the hello message component. I've changed it slightly to use the function component syntax. So we're just using it in this one place. Now, at the time that we built this, everything was hunky dory. It made absolute sense. This is working exactly the way that we want it to be working. But we've gotten feature request, so let's open that up right now. So we hit Trello and asks to add punctuation support. Hey there. We'd like to improve the friendly factor of our personalized greetings. The world has become more exciting over time, and our unaccentuated greetings aren't providing the user experience that we'd like. Our team tried just using punctuation after the component, but the resulting format was off. Not sure why. Okay, well, we can fix this. Let's first see if we can recreate what they tried to do. So we add this and then just try to put a period after this. Now, it might be kind of hard to see on the screen, but we have a period on a new line. It's a little perplexing. So there's nothing that really indicates why this would be happening inside this component. But let's look at our implementation. Oh, we got a div. That's why it's just pushing this onto the next line. Now, we have a little bit of a problem here, is that we could change the implementation. But if we change the implementation, then any of the places that are expecting a behavior where it kind of splits onto the new line are going to break. It'd be nice if we could solve this without really changing this and then having to test all of the other places. So there's a couple of options. We can put this in here. That's a little clunky because this is coming from Data. We'll really have to change this around to be something like Taylor and then put a period after that. That's pretty gross. It works, but it's gross. And honestly, it breaks the notion of what this should be providing, which is just the name, not also punctuation. So since we already have a prop for this, why don't we go ahead and change this to have a punctuation prop and we can put an exclamation there. Now, I know some of you are probably crying right now because punctuation is not particularly descriptive, and you would suggest something like trailing punctuation. And I feel your pain. I'm with you. I know the scars that lead to knowing that preempting that API. So we want trailing punctuation. We're going to have to add that to our component. Let's do that now with props. We also have a props trailing punctuation. Save that, save this, and everything works as expected. Of course, if we provide nothing, then we have the same experience that we had before. This looks great. Let's ship it, send it off. Everybody's happy? Well, we get a new feature. Okay, so another UX request. Add alternate greetings. Howdy UX team again, great work on the last feature. Teams are using punctuation, the punctuation prop all over the place to improve UX. We've even used it with emoji. Oh, great. Cool. That works. We'd like to further customize messages with cute greetings like yo, howdy and what's good? See cuteness at the top of the message. Hey is still a great backup. Can you keep that for existing messages? Okay, cool. I think we could probably manage that. So we have our punctuation prop. Let's get that going back again. We want to have something now where we can customize the first part of the message. So we have something like greeting or let's go with salutation. That feels a little bit more generic, maybe. And we might run into some cases where that might make sense. So let's go generic for this case and see what happens. Let's put our howdy in, save that, and update our component here. We'll use props, salutation, hit save. And there we go. We got howdy. Look at that. Now, what happens if we don't provide anything here? Well, that's not great. That's not what we want. So let's add a default. We know how to do that. Take destruction salutation off of this, provide a default for Hay, and remove the props from there. All right, looking good. Looking good. We have our default, but then also we can override it with a howdy. Perfect. That's exactly what we wanted. We ship it. Everyone's happy again. Okay, next feature. Okay, so now we have a request from the content team. They ask that we improve the grammar. Hey, our marketing team is doing some video content review, is concerned with the punctuation of the user greeting on the dashboard. Instead of, Hey, Joan, we'd like it to say, hey, comma, Joan, what's the best way to fix this? Now, this is a little bit sticky, right? And at first, I'm really grateful that we use trailing punctuation. Now that we may have to insert some additional punctuation, what would that look like? Would we introduce something like salutation punctuation? That seems a little bit odd. I guess this is probably an opportunity where we could push back and say that maybe in this case, it's really just okay to include the punctuation inside of the salutation message. So let's see. Does that provide the use case we want? So we get back to them and say, Hey, you know what? This is probably not something that we need a new API for. Just have the development team change it in the views that you want, and maybe it won't be our problem by the time that we need to update the other views as well. So case closed. We're just going to mark this one as will not fix. Okay, well, we got a new feature. Now, this was actually from design, so it says, have the ability to accept class selectors. Okay. We're collaborating with UX on a project, birthday Bonanza. The goal is to do a one time animation of birthday balloons over the user's name in the main dashboard. Happy birthday, Aaron. With the balloons. We have a new birthday balloons class selector that does the trick. Our prototype is approved with wrapping elements, but we'd like to keep the number of extraneous DIVS to a minimum for future styling efforts. Perfectly reasonable. Could we get hello message to accept a class name prop? Yeah, I think that's perfectly reasonable. And you know what? We're actually going to even do you one better because we know that there may be other attributes that you like to add, like accessibility attributes or an ID. So let's just do this right from the beginning. Let's put a class name on here. Balloon Bonanza. Okay, save that. And we're going to do this. We're going to take off name all the props that we're using. We'll do trailing punctuation and props. Okay, take these off here. No problem. And we're going to spread props over everything. Now, we have that class name applied, but we can do anything else we want as well. We can add style attributes, ideas, et cetera. This is probably the way that the component should have been designed from the beginning. So this is looking great, actually. It's really more reusable now than it ever has been. So, yeah, awesome. Great design. Thank you for showing us the error of our ways. Use the class name. So now we have a new request. Here we go. So this is an accessibility request here at ability to modify markup. Okay, we just concluded a pre launch accessibility audit, and there's a few low hanging fruit that we can solve with semantic markup. One of the targets of interest is hello, message. We have a few teams on the effort right now. Should we move away from the component or can it be adapted to take a different markup, like an h one strong, et cetera. However, the page needs to use it. We want to get this fixed out as soon as possible, so we'd love to know if there's a quick fix. Thanks for your help. All right. Actually, I think there probably is a quick fix. I just read an article about how we can use polymorphic tags or elements inside of our react component. So why don't we do that? In the article, I saw that it uses as, so we need as. Let's just put in a span. Or maybe we can change this to an h one if it was showing at the top of the page. So we pass in an as prop, we'll destruction that as prop, and the default will be our div. Now, this is great because we're providing this default that will make sure that anything that was using it before without providing an as prop is going to have the same functionality. Okay, change this here to a capital as. And here we go. Off to the races. We got this h one in there. That's great. Okay, cool. Yeah, no, we can totally handle that. Accessibility request. Let's do that. Okay, cool. Here we go. Closed. Thank you for coming. I hope that this helped us improve accessibility across the site. We got a new one. This is a bug. Hey, great work on hello message. You saved our butts with those quick fixes. And teams are firing at all cylinders. We have just a few places where updating the markup is causing layout issues. Can you help us diagnose this? PS. I don't know if this is relevant, but there are efforts in place to normalize styling techniques across the product suite. It's a mess right now, but I hear everything would be amazing to work with once everything is converted. So we'll circle back on clean up, but a quick fix is preferable right now. You've done a great job maintaining backward compatibility so far. If there's a backward compatible fix for this, that'd be great. All right, so we jump back into our code, and obviously some of these changes are going to happen when people change the markup from one thing to another. However, we're not providing some default style for them to use in the case that they want to just augment it using the same style. I think that there's probably a way that we could do this. We could just pop a style tag on here. Since we're in a hurry, maybe we can just kind of do it as quickly as possible. Display block. Okay, so then in the case of someone using this with a different type of element and they have something else play, the previous expectations on style are cool. I think we did it, actually. So let's send this along. Unfortunately, it doesn't look like it's going to work for everybody. So we have this style. It's doing inline style, but it's really forcibly doing this. So we have an inheritance problem. Now. Some of the teams are reporting that we have where they were changing the style with a CSS property. Now that we've allowed them to, this is overriding their CSS style. So that's not good. I guess since we have props, we could have some kind of, like, maybe no style prop. If we set that to true, well, then we could kind of not do the default styles. Something like let default style equal display block. And then if we have a no style tag and it happens to be true, we'll default that to false. Maybe we can spread this out. So will that look like no style null and wrap that inside of this like so one more set of curly braces and we're off to the races. So now we can add the no style prop, and then that's going to actually negate the style. We can take it off. Okay, cool. Now we submit this for review, and people notoriously hate it, as I'm sure that you hated it while I was writing it up. So what's another way that we could do this? Oh, we could use delegation. Delegation is a great way to kind of solve this problem with react components. So we could do something like this if there's a style, if we want to provide no style, we could just kind of provide that as an argument. So we got the default, and if you provide me a function, well, then I can give you the default back and you can just ignore it if you want. That's not too bad. It means that we don't have to take this anymore, which is great, and we can kind of get away from this nonsense. So we have our default style. We're going to call a function type of style equals equals function. Then we're going to call style as a function with our default style. Otherwise we're going to merge default style and the styles that have been passed in. So let's take that as an argument. Type of style equals equals function. And then oops, I need that. There we go. Now we have the whole thing working. And this actually satisfies everybody's feelings on the matter. Now this API isn't perfectly intuitive where we would actually take an argument and then intentionally ignore it. However, it is flexible and we can work with this. We can add to the documentation and it does get us what we need without really breaking any of the existing expectations. Okay, cool. So I think we're good. We're going to call this one done. Okay, we got another one from the internationalization efforts. Oh, my gosh. We're almost over the finish line. Your creativity with Quick Fixes has really helped us meet our launch goal. Sure, we're a month behind, but we knew that there would be hiccups. Can't make an omelet without breaking some eggs. Anyway, one of our biggest customers is overseas. We've been kicking the can down the road with greetings for a while, but we need to support RTL or right to left in our dashboard messaging. I know we're so close, but I swear we're almost there. Just one more push. Everything will calm down after launch. You think you can get the new internationalized message into staging this week? Man well, I guess we can. Let's see what else we can do. Let's see. Well, technically, we haven't used children yet, so we can do hello, message here and say we have this function intel greeting. We'll call that this is the function name that we get and we provide the name here. Okay. And then it looks like we can get rid of a lot of this stuff. So we're going to have to define that real quick. Function and it returns. For now, let's just treat it statically howdy name now what do we do on the component side? Well, on the component side, we have to take children now. So we'll pull children off. And I guess we'll have a conditional here for if children is provided, we'll render children. Otherwise we'll render this. We'll have to change that syntax a little bit, all right? And we have everything working the way that I did before. We didn't have to change any of our expectations. Everything is great. However, this does look like a lot of code, doesn't it? We have this gnarly component API now for something that really does nothing at this point. And I wonder what advantage do we get from in the first place doing this instead? We've done a lot of work, but what have we accomplished? We've done a lot to make this component flexible and reusable. All of these things are really important to us. But what have we actually done? We talked about encapsulation, but this component encapsulates nothing of substance. And everything that uses this component is now beholden to this kind of weird bespoke API that uses language that's inscrutable for no discernible historical reason, like trailing punctuation salutation, and a style attribute that takes a function for some reason. And all of this because a component really wasn't the answer that we needed from the beginning. Now I think too often our components look like this just a stack of ternaries techniques and technologies that accumulate to no obvious outcome beyond the generation of more work. And our patterns and egos often lead us to design components that are dead ends instead of through streets. The first time I went through this content, I thought, well, that's great. I'm going to write some takeaways now. And we should make these into Lint rules, right? So props considered harmful. The blog post writes itself you might not need a component number two a banger use composition. Hey, we're getting the hang of this hacker news for sure. No debt ends only through streets. It's a little abstract, but this could maybe be the summary of all of these posts. The problem with that is that rules actually make us pretty bad collaborators. I've noticed a lot of times in my work that the rules we put in place are really just to close the door behind us and not have to communicate with our fellow teammates about decisions that impact everyone. So instead of giving you a handful of new rules that I think that you should observe or think about, I want to throw an error instead and ask you, are you happy with the way your team works? Do you feel that the work is harmonious, sustainable, and reliable? Are you often tasked with reworking the same component over and over again? Are we realizing the full potential of component encapsulation and colocation with the patterns that we're using? Are we just jumping through a bunch of hoops? Are the patterns and practices we use productive. If not, why not now? I asked around in my discord server and on Twitter to find out why people don't throw the error when they see this stuff. Because a lot of people are really smart and they see this stuff all the time and they know the repeated pain that they're experiencing, so why don't they raise it up? Well, here's a few things that we got. I'm just doing what the Linter tells me. It's safer that way. Refactoring is an acceptable form of procrastination. It's my imposter syndrome. Demonstrating mastery of the patterns proves I'm competent. Tech lead read a blog post on a performance enhancement and won't merge a PR without it. I'm just trying to be home by five. More complexity makes me feel more clever. Fast fixes are rewarded. Slow solutions aren't. Cross cutting solutions are arduous. The energy required to reframe the scope of the problem is a lot more energy than it takes to push a patch. I'm an engineer, not a manager. If I can fix it, no matter how hacky, why wouldn't I? Dry dogma criteria comes down, it does not go up. Shift left. My company prefers three rights. The problem isn't code. I think that we all have seen code like this and identify that it is not serving us well. And every time we push some patch to it, we know that we're just kind of extending the surface area of potential problems and it's easy to find someone to blame. I think that we have a cycle of blame inside of our community and our organizations. Seniors blame poorly educated juniors, juniors blame dogmatic, seniors. Managers blame timelines leaders blame market conditions. Corporations blame unreliable communities, and communities blame stingy corporations. There's always someone to blame. Everyone has someone to blame, and we all suffer. The rise of the component has been great, but it's also forced us closer together than we've ever been before. We're all in this immense organizational, cultural and social tension, and it all lands directly inside of these components with all of their colocation. And I believe that problem is costing you. It's costing me, it's costing the companies you work for and the communities that we support. Consultants are really the only ones that make it out of this. With any benefit component, colocation increases collaboration costs, plain and simple. We put a lot of emphasis on topical communication improvements where we feign better listening skills with pleases and thank yous, and thank you for sharing that. But what are we doing to foster true cross cutting communication across teams where not just the acceptance criteria get tossed between departments, but we instead open lines of communication to listen to the pains of our collaborators and attack the root problems that impact all of us? What are we doing to help those below us, above us, and around us? To create a space where ego is low, efficiency is high, and great collaboration is both prized and rewarded? Because if you crack that, you'll be among the productive few to stop making and remaking the most expensive component in the world. Thanks for listening. I'm fantastic, and I hope that this helps. Hey, it's Joe Eames with Ng. Comp. If you liked that video, be sure to click subscribe. Either here or here, somewhere over here. And if you're looking for something more, here's another video for you. Watch here or there or somewhere.