The Weird Things About React

Bookmark

Conditional rendering issues in JSX, forwardRef, serveral ways to create refs, render props (yeah they still exist), higher-order components (do they still exist?), act, non-extendable classes, SuspenseList (well, maybe in 10 years), React.FC and of course our good old friend useEffect. All these weird things are part of our favourite library (not a framework™) and yet we still use and love it. Why actually? Let's talk about. Disclaimer: This is not a very serious talk, mostly …



Transcription


So good morning, everyone. Let's get right into it. Let's talk about the weird things about react. And thanks for the broken committee to allow me to alienate you right in the morning and regret your life choices. But before we do that, briefly about me. I'm Nick Graf. I work on Serenity with a team of three, four. It's end-to-end encrypted. Think of like notion end-to-end encrypted. I'm also an ACAD tutor. And depending who's asking, I'm a consultant or freelancer. And let's continue with me. My journey with react actually started with 0.12, the version, or 0.13. And by that time, everything was really, really awesome. You know, javascript didn't have classes. So we just had like function, create class in react. And it was pretty good. And then 0.14 came along. And then the first thing happened. I was like, that's a warning sign. What's going on? What, 15 now? Why not 1.0? And they knew they did something odd here, because they released this really long blog post about why they're doing this, how Samware works, but they are doing it a bit differently and whatnot. And so either this is like regret or dedication or commitment. And for me, I didn't care. I felt like, OK, at least they know it. They're aware. This is good enough for me. And the world moved on. We had 16, 17, 18. And things were good again. And what I really like about react is that you have react.js.org, the documentation. But all the nitty gritty details, all the thinking behind it, you can find on the inofficial docs, Twitter.com. It's really great. Follow these free profiles, and you will know about the thinking, about the background, everything you really want to know if you're using react over a longer time. Let me give you a couple of examples. Did you know that you can use the key attribute to basically remount components? So if you look at this, this is a very simple component application. But what you do is when you click the button, you're actually updating the ID. So for example, this ID here, if this goes from ABC, a string, to GHI, what happens is you're actually remounting the component. And this is nowhere on the official docs. But once I figured this out, this was fantastic. Because I know you shouldn't use this all of the time. But sometimes it's really, really handy if you have someone that built a really bad component that is using useEffect completely wrong, and you can't fix it, you can just remount the component. Awesome. Very nice trick. And you will not find this on the official docs. Nowhere at all. So I wrote a blog post about it and telling people, don't use it, but this is like inside information that you can leverage if you really know about it. But then you go to Twitter.com, and they actually, Sebastian explains, you're like, yeah, this is a completely valid use case. I was like, what? Why is this not anywhere on the official docs? I found this weird. So I proposed, like, why are you not adding this to the documentation? But thanks to Dan, he actually said he will keep it in mind for the rewrite. So I'm still, it's not there on the beta docs, but I'm looking for it, that eventually it will come, hopefully. And that brings me to the other things. Who of you has seen the new beta docs? Excellent. Who of you has read through it from the beginning to the end? You really should. They are so excellent. You still can learn something there. Every time there's a new section, I go right into it and read it. And I really enjoy it because even, like, I'm doing react since years, and I feel like I'm consulted and I've seen a lot, you know. But I still learn something there. And it's great. So if you take one thing away from today, or at least from this talk, read the docs. It's really, really good. I promised you more examples. Didn't you know that since 18 you can actually return a render undefined and return undefined? So this is a valid component. And okay, that was actually an official blog post, so they mentioned it. But it was like zero mentioning why. And I was like, I felt like null was a great decision. And I really don't want to bark with, like, people accidentally returning undefined and then you have, like, weird bugs. And I was like, come on. Why is this happening? Why is this changed now? Why not a year ago? And there's nothing. And you accept on Twitter.com. I mean, it took them some time. I think it was 15 days or so. But then they actually released an explanation on their RFCs. And this is the second thing. There's a new... Who of you knows about the RFCs? This new react RFCs thingy? Raise your hand. Wow, not too many. Read this. This is excellent. Sometimes it's delayed. But I find it took them a while, only after people, like, asked a lot of questions. But they really explain, like, the thinking. And you can actually propose an RFC by yourself. Like, if you want to see something changed in react. So the beta talks and the RFCs solve this Twitter.com problem. And not the whole Twitter.com problem. But at least the react with the inofficial talk problem. Okay. Let's move on. Completely different topic. Another weird thing about react. Composition. Composition, for me, started, again, my story. Mixins. Who of you has ever seen mixins? This was like 0.12 or 13. This was marvelous. You know? You had two-way data binding. Because we were all coming from angular back then. And so you have to have two-way data binding. We had Memo. Long before you ever seen Memo. And it was great. We were building a lot of things. And mixins were good. And we could compose logic. But then, you know, another blog post came out. So mixins considered harmful. I said, oh, God. Okay. So you have two choices. You either refactor your code base or you quit your job and move on. Yeah. People did different things. So how do we compose now? How do we handle composition? Well, we moved on to higher-order components. And I was totally all in. I was like right away at that point on this hype train with functional programming and higher-order components. It was so beautiful. And you could compose everything. And it was completely unmaintainable. It was terrible. The thing is, I mean, it was good for consulting. You know? A lot of good income. But it was like really shipping something was not a good thing. So we realized, no, this is a bad idea. And Andrew actually joined Twitter and he joined the react team and then he made this announcement higher-order components are a bad idea. So we got rid of them. Well, almost. So we still have mem on forward ref. I wish forward ref wouldn't exist. But that's another story. And at this point, I'm like, am I part of an experiment? Like I'm constantly having to change my code base to get composition right. And yeah. I found this weird. And it didn't stop there, obviously. Then we had render props and I really hated them. It's like, I mean, all this nesting above nesting above nesting. This was horrible. And I never spoke out loud. I have to say that. But like, blah. Render props were the worst thing. So then we got our savior, hooks. And hooks are great. Because they're a concept that is really weird. They're stateful functions to solve our problem with the non-extendable classes that we had before. And all that we can do our templating logic in our business logic code. It's fantastic. But hooks is actually, I'm okay with it. Like hooks is, hooks are good. They have a clear rule set. With like, they should only be used in a react component. There should be no conditional use. Until you actually go to Twitter again and you realize you can use context conditionally. It just, they don't allow you, allow it to you from ESLint. But basically it works and will not cause any problems. You can do it. Still probably not the best idea. But it's all a lie. You know? But in the end, I think hooks is really something that at least I feel comfortable with. And I hope we are almost at the end of this whole composition story. But time will tell. Let's talk about something completely different. Again, another weird thing. Or we come to the weird thing. I love named exports. They're really great. You know, the auto-completion experience in the editor, it's fantastic. And at a point in time, a couple years back, I could agree with all the teams I was working with, we only used named exports. Everyone was on board. It was fantastic. But then this came along. react Lazy. Because react Lazy requires you to have a default export for your component. I was like, no. All our decisions flushed down the toilet and we have to rethink again. And I think with all the teams who went back to having default exports for components, we were not happy. But okay. We accept it. I mean, well, we accepted it. At this point, you also feel like maybe the grass must be greener on the other side. So for example, we looked into angular and then we found like, okay, what's the current version of angular? So you have like 1, 2, 3, no, 1, 2, 4. And you're like, okay. Forget it. Back to react. Let's see how this goes. And yeah. We still do default exports now. I find it weird, but it's okay. And even like, I think a couple days ago there was like a series of tweets where people were like copy pasting the same tweet and tweeting default exports was a mistake in javascript. And I agree. But there's one hint, one trick that I want to show you. If you have actually someone, if you have a component that is a named export and you cannot control it because it's coming from a library, you can actually use named. It looks ugly. It probably confuses the juniors out in your team. It confuses the hell out of them. But still, there's a way to get it done. Why you probably still want to or why we stick to default exports, because all the frameworks prefer named exports anyway. So yeah. It's kind of weird. But we can live with it. Let's move on to the next topic, typescript. I love typescript. It's awesome. I love typing. You know, the security of it, it's great. The one thing that I not always love is the react types. Let me give you an example. You know when you start typing your first react component, you learn, okay, there's react.function component and you do it like this. And then realize, okay, but people don't use this. People use react.fc. And I was like, we don't have fun, funky and funny for function as a keyword in javascript. Why do this? Why can't we have one way of doing things so you can teach one way and you can learn one way and you can be good with it? But this is not the end of the story. Because then, when you actually start to read about how to type components and so on and so forth, you realize a lot of experts, typescript experts, tell you, like, don't do react.fc. So basically, and it all comes down to, like, mostly all of them complaining about one issue that existed in, yeah, spoiler alert. It's solved now. Basically, the types always implicitly, so this is what kind of happened, implicitly react.fc added the implicit children. So if you had a component, like a model, where you really need to have children, we expect them, you could pass them in or you could leave them out. But if you have other components where you don't even make use of children at all, you cannot declare it in any way because it will always be optionally there with react.fc. And so basically what they proposed is use this instead. And you do this and you migrate your whole code base with your team and then you onboard new juniors and they're really, really excited because they feel like, hey, they have an improvement that they can tell you about. Did you know there's react.fc and we could migrate to this? And the only reaction is, like, yeah, let's talk about something else. And you feel really bad for them. But it all changed with, so by the way, the react types are not maintained by the react core team. But they made, whoever is maintaining them, they made a really great decision because with react 18 and breaking change, they sneaked in a change with their types, removing the implicit children. Ta-da! And I was like, hallelujah, solved all my problems, I can go back to react.fc. Why? Because if I have this here, if I have children, I have to now explicitly type them or I can explicitly type them and basically say, like, okay, children's react node. And the thing that's happening here is, if you look at this component, the component uses children and you're basically expected to put in the children. If you do this, everything will be fine. But if you do this here, you will get a typescript error. So it will tell you, like, hey, this component really only works well if you pass in children. So please pass in your children. And you can also do it the other way around. If you leave out the children at all, the beauty is if you do this, it will be fine. But if you do this here, it will give you a warning, hey, you should provide children or you should not provide children because this component doesn't accept any children. So this is a very neat trick. They really fixed the types and it really fits my mental model of basically, like, I mean, this is Wikipedia, but the aim is to prevent operations expecting a certain kind of value from being used with values which that operation does not make sense. You always want to have, like, typescript is a tool to help you to make sense of things and not, like, refresh and then figure out, oh, it doesn't actually use children at all. Yeah. So that was really, really great. The weird things of the weirdest thing about typescript types in react got actually fixed. The thing is now when you upgrade to react 18, you actually have to then change all of your components. And this is the pity again. Like, oh, God, now I have to go through hundreds of thousands of components and fix them. But there's a thing called CodeMod. Who of you has heard of CodeMod? JS code shift. Okay. A bunch of you. It's basically scripts that allow you to run over your whole code base. And the cool thing is they will fix your code. So if you're upgrading to react 18 and upgrade the types, you can basically just run this script upon your source folder and it will be done. And it updates everything. So what does it do? It takes this component, for example, and it updates it to this one. And I was like, yes! Solved all my problems. And then I was like, on a second look, wait a second. This component doesn't actually use children. Everybody is saying here props with children. And I thought, maybe I misused the script or I did something wrong. But I mean, you start investigating. So you look into this type. What is props with children? And then you see the optional children in there again. And I felt like, why? Come on! Are you really doing this to me? Why are you doing this to me? And at least when you do this, have the dignity and call it props with optional children. So I know what's going on. Okay. So not perfect, better. Let's see. Next topic. Let's talk about use effect. Oh, God. We all love use effect. I cannot fix use effect for you. The only thing that I can tell you is a lot of problems come because people don't use the cleanup function. At least this is what I've seen. So one thing that I find very annoying, the people often don't know that they should do a cleanup function. And then they forget it. And it's very easy to miss in a code review. So after a lot of frustration, eventually we decided to let's do something about it. So we could now do ESLint and whatnot. But the easiest way was let's fix the actual react types because we can override it. This is how the react types for use effect basically look like. And what you can see here at the very top right on the second line is destruct or avoid. So you basically like people can leave out the cleanup function and don't have to return it. Don't worry about the types too much. But the one thing I want to tell you is what we could do is we could just fix them. We override it and say, nope, void is not allowed. And then we can also fix the naming. Because come on, in all the documentation it says not destruct, it says cleanup function. So let's name it cleanup function. And then let's not call it effect callback because this is very unspecific. Let's call it use effect callback. I really like to when I'm already in there, I like to fix things anyway. And what does this give you? Is basically you have forced now to return a cleanup function. And so basically if you don't do it, it will give you a nice warning, hey, you're missing a cleanup function basically. And so basically people have to do this. And yes, people still could do this. But if you see this in a code review, at least it's very visible that this is happening. So this is a nice little trick that I wanted to share. It doesn't make react less weird, but it at least makes our lives with use effect saner. And which brings me to the next topic. Warnings. I have a huge love and hate relationship with warnings. All of you probably know this one. Can't perform a react state update on unmounted component. You have dozens of them. This is actually good. This is I like it. Because it really tells you, hey, there's something you did wrong. You can clean it up. But we're not throwing an error, but we're at least giving you a warning. I'm okay with that. This is the love part more. I know I still hate them when I see them, because I know I did wrong. And yes, don't blame me, react. But at least I'm trying to clean up. Okay. But the thing is, I can't stand it when it's coming from a package. This is like so annoying. I will show you. This is like real world situation. This were two warnings that we had to go through every time we just wanted to look in our console logs. This is the second warning. It's a react native fabrication. Why do I have to go through this every time? It's coming from a package. Yes, I reported already the issue. And yes, someone has to do it. But sometimes it's even like really hard to reproduce. It's like, oh, God. And we, well, at least I stood, I was okay with them for some time. And then it was like at some point I have to do something about it. I can't stand this anymore. So I was trying to look up how can I fix this? How can we do something about it? And then I found something out that was very, very interesting. Changing my life at least. Did you know you can patch console log? Fantastic. Love it. And yes, at this point, when I figured this out, I should have done the other thing and talked to my team and see how I fix it. But the first thing we did, or I did, was figure out a way how to prank other people. So basically overwriting console log by clearing the console in almost less than a second. So basically we can paste this in here. And then whenever you try to log something out, you log it out and you want to inspect the output. And it clears away right away. Nice. And you know, the important part of a good prank is it should be annoying enough that they are annoyed, but they should not do something about it. You know? They feel like, okay, I glanced the output. Maybe this is good enough. But like, yeah, it's a fine thing. It's a fine line to make it a good prank. And then of course I didn't want to make it too easy for everyone that encounters it. So I created another version where you can actually not find your, look in your codebase and find anything that is related to console log or clear. So you really make it hard. If you manage to get it into the codebase, they will have a hard time finding this. Please use this. This is completely, okay. I think so. I don't know. Don't sue me. And yeah. So eventually after I had enough fun, I went back to the adult thing. And I felt like, okay, let's actually do something about our annoying warnings. And we patched it. We created a little script that basically patches these warnings for specific components on and so on. You can basically do a little bit of regex pattern matching. And then I felt like, okay, I have to have conference talks this year. What do I do? This is something new. So let's create the library out of it so I can actually have something to announce at the conferences. And this is it. react Reduce Stress. This really exists on npm. There's also a GitHub repository. You can find it. You can use it. And yeah. You can simply get react Reduce Stress and suppress the warnings. Suppress console warnings. And you can select for the hooks order. You can basically pass in which component. And for the unique key in list. Yeah. We were using a library avatar group. They were doing something messing up the children. I was like, oh, God. I reported it. But yeah. I'm not waiting anymore for new versions. And then some react Native stuff that we also suppressed. So yeah. You can use this. This actually works. And if you have concerns, file it back. And put a lot of love into it, like one evening, you know. But it works. And what does it give you? Peace of mind in your console. Which brings me to a related topic. And I think, yeah, this is the last one. So enough with the locks, suppressing locks. But there's another one I want to mention. Who of you, the last weird thing. Who of you uses react strict mode? Not too many. Why? Just kidding. So because reasons, and this is actually copied from the official docs. I mean, most of it is basically just like legacy reasons. If you have an old codebase, strict mode is really good, because it helps you to identify what's going wrong and so on. But the thing is, there's two things that are brand new since react 18. One is basically detecting unexpected side effects and ensuring reusable state. And what it does is, if you're using strict mode in development in react 18, it re-renders your component twice, and it also runs the use effect and the use layer effect twice. I mean, the use layer effect usually runs only if you're committed to DOM. But apparently then it's rendered twice. I don't think it's actually committed twice to the DOM. But it's like it's running the use layer and use effect twice. And this has a good purpose, because a lot of us are abusing use effect and then doing things that should not run twice. And then so if you enable strict mode, you will basically see a lot of use effect situations breaking. And this is really annoying. But it has a purpose that basically a lot of new features that will come with react, like offscreen component and so on. So you can pre-render pages, or you can things that are not on the page don't have to be rendered. So you can have faster rendering, faster things on the DOM, faster output on the DOM. All these kind of things expect you to have use effect, not basically have any weird side effects and do things badly. But the problem is, and I understand this, and OK, we basically need to clean up our code. And I get this. But the problem is people don't get it. There is no hint that this is happening. If you upgrade to react 18, or if you just install it in a new version, in a brand new project, you have no information that this, why this is happening or so. And people don't get it. I mean, this is a real conversation from a friend that basically lost the day because he was building a video player in his application. And I don't know what he did, but the mount effect, the mount use effect basically was initiating the video player twice, and the video player could handle it, and yada, yada, yada. And a couple of swear words that I had to black out. And I was like, why is there no, I mean, we have a console log for everything, but why is there no console log for this? We are showing people, if they don't have the dev tools and you're running in dev mode, we are showing them, please install the dev tools. But we are not giving them any information about why this double rendering is happening. And you know why? It's only happening in dev mode. It's not happening in production. So you actually have different behavior if you run in production or not. So this time, I did the other thing. I actually went to the repository of react.js, opened an issue, I proposed, can we have a console log for this and so on. There was not much feedback. It's a couple of weeks old. Maybe nobody from the react team has seen it. But I already have react Reduce Stress. So I thought, well, I can fix it myself. Because what we can do is we can extend react Reduce Stress with Reduce Stress Component that you can actually put into your code. So all the new juniors that will come along if you're using strict mode, so we can import Reduce Stress. You just have to add a component there. And what it will do is if you're in strict mode, if you're in strict mode in development mode, this is completely not doing anything, it will give you this hint. Because you're using strict mode in development, react will unmount and remount every component whenever the component mounts. Basically helping your developers to figure out what is going on. And you know, again, I put a lot of love into it. Two evenings or so. And it has a couple of features. SMDS, who have heard of it? Strict mode detection system. Where did I find this? It's actually in the react core. And you know what they do? They overwrite in console.log to catch if the strict mode lock is happening. It's so awesome. It has dark mode support. For real. So the console, the red, is changing slightly in the console. And it only supports modern browsers. So Firefox, Chrome, Brave, and Edge. We don't support Safari or Internet Explorer. Yeah. And this is basically it. What's the conclusion for you? There was a lot of like mumble bumble. Read the react docs. Check out the RFCs. Read the working group. Have fun pranking someone with console.log. And install react Reduce Stress. And despite I'm having like this was a 30 minute rant here, I want to say it's been quite a ride. I learned a lot. It was a lot of fun. And I will actually stick around. react is awesome. It has its flaws. But it is a super interesting journey. And I learned a lot. And I'm Nick Graf. And I hope you enjoyed the day. Thank you very much. Amazing. Thank you so much, Nick. Is this thing on? Please step into my office. We have a couple minutes only. But there are a couple questions on the Slido from the audience. Remember it's slide.do and the code is 0212 if you want to ask a question. Nick, when we teach new react devs, should they learn about these weirdnesses or should we hide that until they're over the point of no return? Definitely over the point of no return. You're not going to a date and tell the weirdest thing about you. Yeah, I think... Yes. You want to have a subtle introduction. And then you can tell people more on time. I mean, use effect is something you have to tell them right away. And maybe if someone is new to react, don't introduce them to use effect right away. But keep that to the back and focus on the things that are easy and keep people going. You want to keep up the happiness, because this is how people learn best, I think. I think that's a good advice. The other question we have is how do you detect if the app is currently running in strict mode? Yeah. It's really this... There's a console log. Just check out the code. But you basically... There's a console log that is happening, I think. And then you do it like this. Oh, yeah. Oh, no. It's a warning from a legacy component that is basically deprecated. So we are detecting if the legacy component is... So react Reduce Stress uses a legacy component that should be deprecated. And then it throws a warning and we're detecting if the warning is thrown. And this is how we're detecting if strict mode is running. Is this... Not. But this is in a react core test. So it's like, okay, this seems to be the best way. Let's copy and paste it. There's no internal hidden variable that you can use to figure it out. Yeah. Fair. There's a couple of interesting side questions. What's your take on rescript at this stage? So for context, I was part of the early Reason ML community. And rescript is basically a successor to it. And I love rescript. I love good type systems. And it's really great. But right now, I'm not using it. Just because I'm having a product and I have developers that are... And we're familiar with typescript, but not rescript. And onboarding them to rescript would have taken a lot of time. And in the end, it was a very practical decision to not go with it. I mean, I love type systems. I love to write clean code. But yeah. Sometimes the practical thing is just easier and better. Or yeah. It made more sense. That makes sense. Sometimes you have to be practical. That is about all the time we have for questions. But Nick will be in the speaker room by the reception for in real life... Yes. One-to-one questions. Thank you, Nick. Thank you very much. Please. Thank you.
34 min
02 Dec, 2022

Check out more articles and videos

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

Workshops on related topic