1. Introduction to React and Serenity
Today, we're going to talk about the weird things about React. I work on Serenity, a notion-like tool that is end-to-end encrypted. We use React and React Native for web, iOS, and Android development. I'm also an ACAD tutor and available for consulting or freelance work. Feel free to reach out.
Today, we're going to talk about the weird things about React. I'm Nick, short introduction. Yes, I work on Serenity. It's basically, think of this like a notion or confluence, but actually end to end encrypted. And of course, we use React, React Native, actually, in this case. So we compile to Web and React Native or iOS and Android App. And I'm also an ACAD tutor, so you can find some courses for me. And depending on who's asking, I'm either a consultant or freelance, so yeah. If you need some help, feel free to reach out.
2. React Journey and Interesting Features
My journey with React started with version 0.12 or 0.13. I enjoyed using React and the official docs on twitter.com. Let me give you three examples of interesting things you may not know about React. One example is using the Keyprop to remount components.
Enough about me, well, not totally. Let's actually begin. My journey started with, I think, 0.12 or 0.13 with React. And that time was awesome. You know, you had this like create component class and React was very clear. And everything was good. Really enjoyed it.
Then 0.14 came along. And these were good times. And then came the first warning sign. What? Why not 1.0? Yeah, but they made this blog post, this like really, really long blog post about why they're doing this and basically explain Semver and so on. And I felt like, OK, so they probably, I mean why they're doing this, they must feel guilty. Or they must see that they're doing something wrong. And they're putting a lot of dedication in it. And so I'm fine with that. Let's move on. And after that, the world was OK again. 16, 17, 18, things are good. Yeah, the world is awesome.
And one thing that I really loved about React was the official docs, twitter.com. And you can really find a lot of great content there that you don't find on React.js or IG or so. Let me give you three examples. I'm going to run through this quickly and then get to more weird stuff. So did you know that you actually can use the Keyprop to remount components? This is a fantastic one. You don't find this anywhere. Well, there's one place. So what does this mean? Short, brief example. If you hit this application, it's very simple. It has a button. You can generate random IDs.
3. Using Keyprop to Remount Components
You can use the Keyprop to remount components in React. It's not documented, but it's considered a valid use case. Sebastian Markbash recommends using it in certain situations. The new beta docs for React are amazing, with many examples and tutorials. They provide a deeper understanding of React.
And we directly put it on the some component, whatever, as a Keyprop. And we put this ID that changes. But the thing is, if we change, let's say, the content, the actual content is A, B, C, and we change it to GHI, what's happening is, the component will remount. And when I figured this out, I don't know if someone told it to me or so, I was like, wow, this is a magic tool. I mean, you probably shouldn't use it all the time, but sometimes it's really handy. If you have someone else's component and they actually screwed up the use effect, you can use this to give it a fresh thought. And of course, on the official docs, I learned that this actually is OKish to do. It's not documented, but they think this is a use case where that's fine. So Sebastian Markbash mentioned that if you have this main detail situation, it's good to use. I'm still not sure, because I think since it's undocumented, yeah, I don't know. I think people would not get what's happening and then might be weirded out. But the good thing is they replied, hey, why not add it to the docs. And thanks to our angel Dan, he replied, hey, he's doing it probably, yeah. And I don't know if you have seen them, but the new beta docs, they are amazing. They are so good and they have so many examples and tutorials that they can go through. They really, really like dig in one level deeper and teach you a lot. And it's, yeah, this is basically half the solution of like how to use React.
4. Flush Sync and Returning Undefined in React
There's a nice little trick called flush sync that allows you to commit updates to the DOM before painting. It's not documented in the new beta docs, but you can find it on Twitter. Another interesting feature in React 18 is the ability to return undefined in components. This was explained by Ricky in a Twitter thread and further discussed in the working group. The working group provides valuable insights into the reasoning behind API changes.
In one more example, there's one more way to avoid use effect that David, in the morning, hasn't shown. And this is like flush sync. You, yeah, what you can do with it you can run flush sync and then set some set state update in there. And what it will do is will actually commit it to the DOM. But again, it's like before you paint it. So what you can do is you can use it instead of just use layout effect and scroll, for example, to the last message if you're having a chat application. So it's a quite nice. It comes from React DOM, so if you're using React Native, it doesn't work. But it's a nice little trick.
So the main question is like how did David not know about this. And the thing is it wasn't on Twitter. It was on YouTube. But it was a coding session that Dan did. Yeah, that was recorded. And then someone in my React workshop told me about it and I figured it out. So I felt obligated to put it there. So I asked Dan why we're not adding this to the new beta docs. And he replied there's a couple of good reasons why you actually don't want to do it. So FlushSync might not be the right tool for the job. But at least now it's there on Twitter and you can find it.
Yeah, last example is about like since React 18 you can return undefined in your components. And so basically this would be a valid app. This is a valid React component now. And when this came out there was this like line, I think it was a paragraph and then a line and a commit log and so on. And I felt like OK, but why? I really want to know like why you're doing this to me? Like returning null was actually completely fine. I really enjoyed the experience here and the API and it made total sense and there was nothing. No reasoning like what the heck is going on? Luckily, Ricky, a couple of days later on Twitter posted because people were actually asking what's going on. He replied, yeah, I will answer this and then again, couple days more later he actually did. And when he did do it in the second thing that you start to read because this is where often the why is explained now, the working group. So I think the working group is basically where they make the proposals but you also find a lot of content and then in the discussions of the reasoning why are certain things, why are API changes the way they are and what is the reasoning behind it? So the good thing is the whole documentation thing was weird, but I think we're getting there like solving in the better, beta docks are great and the working group is an amazing solution to understand the why more.
5. React Composition Story
The composition story in React started with mixins, which allowed for features like two-way data binding. However, they were deprecated due to being considered harmful. Next, higher-order components were introduced, which were initially exciting but became convoluted and unmaintainable in large applications.
So let's move on, a completely different topic, composition. And the composition story in React is also really weird. It started for me with mixins. Who of you was there when there were mixins? Wow, not that many. Okay, so mixins were this thing that you could put in your create class component and it enabled awesome features like Angular's, or I think we had to do it because of Angular, two-way data binding. So you could directly connect state to your input and you don't have to go for this cycle. Yeah, it was kind of weird. I actually didn't use it too much, but in some cases.
6. React Composition Challenges
We had memo before memo, a pure random mixin. But then mixins were deprecated, and we moved to higher order components. However, they became convoluted and unmaintainable in large applications.
And we had memo before memo, a pure random mixin was amazing. But, then something happened, another blog post. And what does it mean? Well, it's gone. So they figured out, yeah, they think mixins are harmful and goodbye mixins, so we're gonna deprecate them. Awesome. Let's update the code base. Where should we go to? The solution, higher order components. And I was totally hyped back then. I loved them. This was exactly at the time where we really digged into functionality programming. So higher order functions and all this kind of stuff, like wow! The only problem is, if you build large applications with it, it got so convoluted and complicated, it was basically completely unmaintainable. And it was good for consulting. I got gigs where developers jump off the project two weeks before the release and then you could make good money with it. But maybe not for your own projects.
7. Transitioning from HOK to Hooks
We got rid of all the hooks again, except for memo and forward ref. I still don't understand why forward ref exists. We moved from higher order components to render props, which I hated because of the painful nesting. The only good part was using a plug-in in VS Code to manage the convoluted deepness structure of my components.
So there was no blog post, but at least there's an update to the Readme of recompose where it was announced that you should not use it and you should move on. So we got rid of all the hooks again, well, almost. We still kept memo and forward ref. Memo, I understand. Forward ref. I wish it would just be part of it, but OK. I understand. We don't want to be. I actually don't know. I have to ask some of them on Twitter, and then we'll learn why forward ref still exists. I searched for it. I haven't found it. So where do we move from higher order components? We still have to figure out this composition, well, we had to figure out this composition problem. And then we went on to something that I really, really, really hated, and that was render props. Oh boy. The nesting there, it was so painful. And yeah, I'm really glad we got rid of it. And the only good part that I remember, or that is left of this time, at least for me, is like I installed this plug-in in VS Code that does colorize all my parentheses and brackets, because this is the only way to like manage the convoluted deepness structure of my components back then.
8. Hooks, JSX, and Nint Exports
Hooks are amazing! Stateful functions are great, except when explaining them to back-end engineers. JSX can be confusing, but hooks provide clarity. However, there are exceptions, like using use context conditionally. The composition story with hooks is satisfying, and the new proposal is intriguing. Change is still incoming. Let's talk about nint exports and consistency.
So we got our savior. Everyone remembers this, hopefully. Hooks. I mean, what isn't amazing about them? Stateful functions. Who does not want to have stateful functions? You know? It's, yeah. You can't loop them. You can't have them conditional. So, OK, there are some downsides. But yeah, in general, they are pretty good. Except when you try to explain that to someone like back-end engineer that usually has working with stateless functions, which is like the normal default.
Yeah, and they are not too happy about it, but then you're already very excited about the conversation and tell them about your non-extendable classes that you deprecated with your stateful functions. And yeah, if you then move on to JSX, you basically lost a friend because they don't understand at all what we're doing there. But hooks are great. They are very clear. They should be used in a React function. They should start with use, and they should not be used conditionally. Well, except on Twitter you learn it's all a lie because you can use use context, actually conditionally. They will scream at you, but you can. You should not. And I'm not encouraging you to do it, but you can.
OK, so the docs are solved. Like, the composition story, I don't know, like, it feels like I'm happy with hooks. I dig it. And the new proposal, as we just heard, also looks interesting. Let's see where we go. But it seems like we're not done yet. Change is still incoming. Let's move on to something completely different. Nint exports, you know. I love my nint exports, and I love consistency.
9. React Exports and TypeScript
I love that all the teams agreed that nint exports is the best experience. The autocompletion in VS Code is amazing. React Lazy caused some issues with default exports, leading to discussions and exploration of other frameworks. However, React Lazy can still be used with named exports. TypeScript is another topic of interest for TypeScript fans.
I love that all the teams that I worked with a couple years back, we all agreed, like, nint exports is the best experience. The autocompletion for importing stuff is amazing because VS Code can really, like, you just start typing it, and it can find it in other modules and automatically imports your component or your function or whatever. And we had a consistent code base, and then React Lazy came along. And everything was screwed again because React Lazy actually requires you to use the default export. And yeah, by then, at this point, so basically what happened is again, a lot of discussion in Teams. How do we do this? Do we move everything now back to default exports because we now have consistency or only React components? And, and, and, and, and, a lot of discussions. But this time, you feel like, OK, the grass must be greener on the other side. So you start to look into Angular. And you start to like, which version are they actually using? And then you see one, two, four. And you feel like, OK, it's the same story. Let's go back. So you go back to React. And you dig deeper. And you actually figure out you can actually use React Lazy Weave named exports. It's just, it's very clumsy. But it's possible. So maybe you still have your discussion about default exports on the components. And at least in our case, this is what happened. But even if you want to lazy load an external component that is just a named export, at least you can do it. It's amazing. Awesome. But the default export still makes sense. Because I mean if you use Next or Remix, they still want you to use the default export. So it makes sense to at least stay consistent. But this little trick at least solved my problem in that case. So it's weird, but OK. Let's move on.
Next big topic, TypeScript. I love types. I'm a big TypeScript fan.
10. React Types and Aliases
I love other things more, but TypeScript is great. Let's talk about the React types. You have React dot function component. But it's too annoying and too long, so you would rather want to use React dot fc. And I really enjoy when there are multiple ways of doing the same thing.
I love other things more, but TypeScript is great. So let's talk about the React types. Well, how do we type a React component? Obviously, it's very clear. You have React dot function component. In the type parameter generics, you put in the props. That's awesome. But then actually it's too annoying and too long, so you would rather want to use React dot fc. And I really, really, really enjoy when there are multiple ways of doing the same thing. This is great. And I will soon put up a proposal in JavaScript that also adds aliases for function, namely fun, funky, and you can add yours if you want to. Yeah.
11. React Component Typing and Implicit Children
A lot of TypeScript experts advise against using React dot fc and recommend typing the function with 'if props' instead. The main problem with using React dot fc is the implicit children. When working with juniors, they may discover react.fc and propose it as an improvement, but you have to discourage them. The unimaginable happened with React 18 types: they removed the implicit children.
So this is how you type a React component, except when you actually realize that a lot of TypeScript experts that are doing React tell you, don't do it. Don't do it this way. Don't use React dot fc. You're like, OK. And the interesting thing is the main problem that's like, I mean, there's some other smaller issues. Everyone has their concerns. But the one thing that comes up consistently is the implicit children. I will explain it in a bit. But basically what they tell you is you should do this instead. You should just type the function with if props is your props. And that's it. OK. So far, so good. What is the problem then?
Well, the problem then is if you're working with juniors, for example, and you see your code base, they just do what everyone else is doing in the code base. And then eventually, they learn, they figure it out. There is react.fc. So they come up to you, and they're really shining. They're happy because they have a proposal for the code base how to improve it. And then they found something. And then you can discourage them. It's the only thing that you can do. Well, you shouldn't use it. And you start to explain it, and yada, yada, yada. And yeah, you lost another half hour on nothing. But the thing is, and then this question comes, but why does it exist, then? And then the only thing you can do is just this. Let's move on to another topic. But then the unimaginable thing happened.
What happened? With the React 18 types, they also made a breaking change, and they removed the implicit children. Wow. I was excited.
12. React Children and Type System
You can now explicitly mention whether you want children in your React component. If you're creating a popover or modal component, it makes sense to have children. Conversely, if you're not expecting any children, you can explicitly state that and TypeScript will throw an error if children are passed in. This aligns with the aim of a type system to prevent operations from being used with values that don't make sense.
It's like, fantastic. I was really, really happy. Why is this a thing? Why is this relevant? So let's say you have a component, and now you can use React.fc again. And you're using children in there. Now you explicitly have to mention it. I mean, you can still make it optional if you want to have optional children, but you also can make it mandatory. So what does this mean, basically here.
I have children in my component. Pretty nice, but if you do this here, so if someone is using your component, and they're doing this here, TypeScript will scream at them. Like, you need to pass in children, and of course, it doesn't make sense always, but if you're creating like a popover or a modal component, the whole thing without children makes like, almost no sense. So this is where it's kind of useful, and especially the other way around, it's even better. If you're not expecting any children, you don't do anything with them, then you can basically explicitly tell, hey, I don't want children. If you pass this in, like, show me an error. So if you do this, it's all good. If you do this, as someone that is using this component, TypeScript will scream at you. Ta-dah, don't pass in children. Ah-ha. And this is exactly like my mental model of like a type system, and I mean, you can also, I feel validated by reading Wikipedia. The aim is to prevent operations expecting a certain kind of value from being used with values which the operation does not make sense. Yes. We want to make sure that everything makes sense. Awesome.
13. React Code Mod and Unexpected Changes
This change was amazing. They built a code mod that fixes breaking changes in your code base. It works almost 100% of the time, except for rare cases. However, there was one thing that bothered me. The code mod added props with children even though I wasn't using children. It's frustrating when small details like this are overlooked.
So, this change was amazing. I enjoyed it. Perfect. Let's move on. And the best part about it is, they even built a code mod. Who has ever heard of a code mod or just code shift? Not too many people, so basically this is a script that you can run over your whole code base, and it fixes all your breaking changes. This is the idea. And it's not actually just regular expressions, but it works on the EST, so it's actually pretty smart, and this makes it really, really nice to use. And that means also that it works almost 100% of the time. Or it should actually be 100% of the time, except you're doing something really, really weird. And what this did, so I ran this over my code base after upgrading to React 18, awesome, awesome, awesome, and then this happened. So the script did this. Basically going from React fc props, we're going to React, so we do a type parameter with a type parameter. OK, I can live with that. That's probably the easiest way for them to move on and fix it. But there's one little thing that really bugged me. I'm not using children in here. What do you mean you're adding props with children here? OK, so must be a mistake, obviously, like the code model is broken or whatever. And you start to dig a bit and you see props with children as optional children again. And I feel like, haven't you learned nothing? It's like, why? Why are you doing this to me again? It's like, at least name it props with optional children. This would have been just a little thing. It's just many, many tiny, tiny details. Then I don't have to get emotional about it, you know?
14. Enforcing Cleanup Function in useEffect
I want to enforce writing the cleanup function in useEffect by removing the option to not return a function. I also fixed the naming to make it more consistent. This way, people will be reminded to include the cleanup function and make it easier to find issues during code reviews.
So we all know you should clean up your use effect because then it can cause problems now, in the future especially. I mean, this is clearly a memory leak. So I want to show you something that I haven't proposed to my team yet, but I wanted to do, but time, and I'm definitely going to do this.
So I digged in, and one thing that I thought of is, maybe we can enforce people to actually always write the cleanup effect, the cleanup function, because then it becomes more obvious that you actually should do it. So I digged into how can I overwrite the React types, and I found this. Basically I copied the React types directly from the React types, and I created an index.d.ts file, and this allows you to overwrite the React module, useEffect. And this is basically the signature. And the thing that I want to do now is, I want to just remove the option to not return a function in useEffect. So we just take away the void, and yeah, I'll show you in a second what this means. And then I felt obligated to actually fix the naming, because, I mean, come on, everywhere in the docs it says a cleanup function, and here it's destructor. People will be so confused about this. So let's call it Cleanup Function. And let's actually call it useEffectCallback and not EffectCallback. OK. And what this does, if you have this function that you have seen before that doesn't return this useEffect, that doesn't return a function in the function, this will actually scream at you again. And yes, you have sometimes useEffect where you actually don't want to do anything in the Cleanup Function. But at least in our case, the code is so rare that I think it would be better. So you kind of force people to actually do it. And yes, they could do this here. But in a code review, this is easier to point out and easier to find, and you can find things. So I think this is, I don't know if this will fly. But at least I want to try it. You know, I'm having fun patching things.
15. Dealing with Annoying Warnings
I'm having fun patching things, but warnings can be annoying, especially when they come from packages and you can't do anything about them. It's frustrating when they clutter your console while debugging. This has been our experience for weeks. I wish there was a way to fix it.
You know, I'm having fun patching things. Which makes me, I'm over time but soon we're done. One more thing, warnings. My love and hate relationship to warnings. So who of you has seen this here? You know, you're doing a state updates that is in a component that actually has been unmounted already and so on. And I think this is actually useful. I really enjoy this. I like this. This is great. So the thing is it's not great if it's coming from a package. Because he can't do anything about it. If you're already on the latest version, of course you can make a reproducible issue about it and yada, yada, yada. But it's like it's still bugging your console. And I mean this is a real world situation. We have been there for weeks. We were on the latest package versions with everything and so on. And this was our experience every time trying to debug something with console.log. This was like two warnings. I was like really annoyed. It's like coming from packages. I can do nothing about it. This is where it starts. Oh God, so yeah.
16. Patching Console.log and React Reduce Stress
I discovered a way to patch console.log and created a script to overwrite it and clear the log after a specific time. It's a fun prank to annoy your team. I also made the script unsearchable for console, log, or clear. Feel free to use it and share improvements. I then decided to talk to my team and patch console.log, console.warn, and console.error. Additionally, I created React Reduce Stress, which was launched today at version 2.0.
And then I felt like OK, I have to do something about it. I reasearched a bit and did you know that you can actually patch console.log? Love this. And once I figured this out I actually should have done the adult thing and like talk to my team and discuss with them how can fix our warnings and hide them and maybe at least for some time. But then I created this script. This is a lot more fun. So if you put this in your code base, what does it do? Yeah, and you can then copy and paste it later. Just come up to me and I will send it to you or post it on Twitter. So this script overwrites console log and after 702 milliseconds, it just clears it out. OK, this is not perfect. But a good prank is it should be long enough that they can see it and they're not immediately taking action, but annoying enough that it's like exactly that they're not taking action. It's really annoying. And this is part of a good prank. And of course, I invested more because I really wanted to make sure people don't find it. So this is the same script, but written in a way that if they search for console, for log, or for clear, they will not find it. Yeah, so please take this. I put some effort in, you know? Please take this and prank your team with it. And if you make improvements, I have some ideas. Like if the content of the log is longer, then you can keep it around for a bit longer. And if it's shorter, then the timer should be shorter. So if you do this, feel free to come up to me. And we can do some code sharing. Let's embrace open source. Yeah, so MIT licensed. Feel free to take it. And then I went back to the adult thing, you know? So I actually found like, OK, let's talk to the team. And we're going to patch our console log, and console one, and console error. And then I felt like, OK, I should do something for you as well. And I really need to release something at conferences this fall. So I created React Reduce Stress. Actually, today we launched 2.0.
17. React Console Warnings and Double Rendering
And what it allows you to do is there's an API. You can get a suppressed console warnings. For hooks, order unique key in a list, use native driver. Peace of mind in your console. The problem is people don't get it. React and React 18 now renders twice. Could we not have made his experience easier? What? Console lock would have solved this. We have console locks for everything, but not this.
And what it allows you to do is there's an API. You can get this, you can input this function. So it's really on NPM. It's a thing, you know? You can get a suppressed console warnings. And then you can, for hooks, order unique key in a list, use native driver. This is React Native. On set native props, you can actually suppress the warnings. And what does it give you? Peace of mind in your console. Excellent.
So last thing, for real. Who of you uses strict mode? Well, why? OK, don't worry. Just kidding. But actually, what are the reasons? So the first ones are just like, let's just stop. So OK, we got rid of the let's just stop already, so why do I care? Well, because of this double rendering. And yes, I understand. They want to bring in this off screen thing, and they couldn't do the breaking change in between. Otherwise, we had 19. So it's better to do it right away with 18 and yada, yada, yada. But the problem, so basically these are the last two points.
The problem is people don't get it. This is like real conversation from a friend of mine and me trying to explain me that React and React 18 now renders twice. And he just lost a day, and then a couple of swear words that I had to black out. And he was frustrated. He just uses React, and he doesn't read the blog posts and what not and so on. And he's just a user. And I felt like I mean, could we not have made his experience easier? What? Console lock would have solved this. And we have console locks for everything, but not this. Come on. Come on. I mean, even if you like, if you don't have the dev tools, we directly point to like, you should install the dev tools.
18. React-reduced Stress and Conclusion
I created an issue on the React repository about a warning, but received no reaction. However, I have React-reduced stress, which can help juniors avoid losing time. It features SMDS, a strict mode detection system, and dark mode support. I encourage you to read the new docs, join the working group, prank your team with a console log update, and install React-reduced stress. React has been a learning journey for me, and I will continue to contribute.
Come on. And not a warning. So this time, I actually did the adult thing. I created an issue on the React repository. It's there since a bit more than a month, and no reaction. But that's OK. I can live with it because I have React-reduced stress.
So what I can do is I obviously can create a new feature in React-reduced stress, which let's import it, and then you will see it. We get React-reduced stress as a component from React-reduced stress. We can edit as a component in there, and what it does is it gives you exactly this warning. It tells you like, hey, there's this double rendering. And there's a link to the official docs explaining why this is actually relevant. And yeah, I hope this helps a bunch of juniors of yours to not lose a day, or two, or three.
Let's talk about the features of it, because, again, I put some love in. It comes with SMDS. Never heard of it? Yeah. Strict mode detection system. Strict mode detection system, I stole, or like, it's open source, I got directly from the React codebase. What are they doing? They're catching console logs to figure out if you're actually in these tests, if strict mode is active. So I took the whole thing, basically used it in reduced stress. And yeah, more love I put in. It actually has dark mode support, so the red color on the log is different. And it has support for modern browsers, so no Internet Explorer or Safari.
Yeah, and that basically leads me to the conclusion of today. What should you take away from all of this weird mumble bumble that I came up with here? You should read the new docs. You should read the working group, because it's really, really helpful. You should definitely honor me in pranking your team with a console log update. And you should install reduce stress. This gets profit. And about me personally, I mean React is really weird in some cases, but I learned a lot on the way. And it actually has been quite a ride. And I will stick around for a foreseeable future and continue to ramp and patch things and have fun. I'm Nic Graf. I hope you enjoyed this talk, and thank you very much for listening.
Comments