Intermediate React, v6

Creating a Markdown Preview App

Intermediate React, v6

Lesson Description

The "Creating a Markdown Preview App" Lesson is part of the full, Intermediate React, v6 course featured in this preview video. Here's what you'd learn in this lesson:

Brian demonstrates a performance issue with a React app that re-renders a Markdown preview component every time the user types in a text area. He shows how the UI becomes janky and slow when the rendering becomes expensive. Brian also discusses the use of the `dangerouslySetInnerHTML` API and the potential security risks associated with it.

Preview
Close

Transcript from the "Creating a Markdown Preview App" Lesson

[00:00:00]
>> Brian Holt: We're gonna show you a couple of tools of how to do this. This is memo, useMemo and useCallback. For all of these, we're gonna have like little starter templates. Cause again, I'm not gonna have you recode your vite config every single time. We have done this ad nauseum both between the last course and this course.

[00:00:18]
So I have a little starter template for each one of these. So if you're not familiar with GitHub, it's really easy to just come in here and say, code, download a zip, which is exactly what I'm gonna do, and then I'm going to open this NVS Code. Project Starter is the one that we're carrying about now, and we're gonna do perf first.

[00:00:42]
So we're gonna be in VS Code, and here we go. We have my project nice and ready to go. First thing, MPMI, and there we go. Nothing super special here, vite. Marked, we're gonna be rendering Markdown like a Markdown preview. React, react- dom and vite, and that's about it.

[00:01:05]
So you have your Client.jsx, this is all this is doing is just rendering it to the client. I have a very long markdown file for us to render. And App.jsx, which has nothing in it at the moment. Again, if we go back and look at my code here, or my page, I have the completed project here.

[00:01:23]
So if you wanna go and compare what I've written, or anything like that, this is all written here that you can see the final results there. Was anyone really hoping to write that V config? They were just, really pumped about it and I just ruined this for you.

[00:01:39]
If it is, I just say, what's wrong with you? [LAUGH] You're broken the same way I am, probably. I actually really like build tools. Okay, here we go. So let's go hop into our editor, and we're gonna make a new file first. We're gonna call this MarkdownPreview.jsx, okay?

[00:02:08]
And we're gonna make this thing at the top called JANK-DELAY. So, JANK is actually a technical term now, before it was just something that was like that looks janky right? But they call it JANK, I don't think there's another term for it. When you scroll down and like pauses and jumps, they call that JANK, right?

[00:02:27]
So we're actually gonna introduce intentionally JANK into our code. So export, default, function, markdownPreview. Render and options.
>> Brian Holt: So const, and we're gonna make this thing called expensiveRender. And this is gonna be a function that all it's gonna do is it's gonna say const start = performance.now. If you're not familiar, there's a performance API in your browser that lets you fine-tune, measure things.

[00:03:12]
And we're just gonna make it an empty while loop, while the JANK isn't there yet, right? So while performance.now- start JANK DELAY. So what's this gonna do? This is just gonna keep running, it's gonna tie up the thread, right, for 100 milliseconds. This is to simulate something like that's really expensive and really busy.

[00:03:42]
Cuz, again, I tried really hard to get make my markdown complex enough, and I couldn't get it to JANK on my laptop. So maybe someone has an older laptop for me. This is like an m3 MacBook, and then you have to return null because it needs to be a valid React component.

[00:03:59]
You can play with this as well, turn up to like 150, 500, and something like that, you can turn it down as well. Return div, I even tried doing a Three.js, I built an entire Three.js. It's like this is definitely in a JANK if I try and re-render this a bunch of time?

[00:04:14]
No, I don't know what they did, but three works great now. It's just the number of GPU cores. It must be, it was wild. I was really impressed with that. I was wondering like a car, it was like re-rendering it continually really well. So last render, we're gonna just put this in here so you can see how frequently.

[00:04:33]
This is technically like bad code, because this is going to be different every time that you re-render it. But I want you to see how frequently it's re-rendering, okay? And then we're gonna say div, class name = markdown-preview.
>> Brian Holt: And we were talking about this before. This is actually how you, intentionally, do dangerously set inner HTML.

[00:04:58]
We're gonna do that, cuz this is markdown, right? In theory you can trust markdown. In theory, this is how they get you. This API is intentionally opaque. They do this so that they really don't want you to do this. Render options.text, we're also gonna change the style to be equal to.

[00:05:19]
So, color : options.theme, and then underneath it, we're going to put expensiveRender.
>> Brian Holt: So every time this re-renders, right, you're gonna run this like intentionally janking sort of thing. This still makes me laugh. Dangerously set in our HTML. They were very explicit about that. They have an API in there called React Internals, do not use this, or you'll be fired.

[00:05:52]
I think that they have changed now. Do not use this, or they call something else because someone complained that firing was not a good thing. I just thought it was funny, but it's probably a good point. You have to be very aware that you're doing this because cross-site scripting is a real thing.

[00:06:14]
So if you're not careful with this, you will open yourself up to cross-site scripting. Okay, app.jsx, let's go build that very quickly. And we're going to import use effect from react. We're going to import marked, which is the name of the markdown library we're going to be using from marked.

[00:06:41]
We're going to import, I've reacted on there twice, so you can just put it in here, useState.
>> Brian Holt: Import MarkdownPreview from MarkdownPreview, cool. And Import MarkdownContent from./markdownContent, which is just that long markdown file that I made for you.
>> Brian Holt: Export default function App. Okay, and let's just run, a little bit of React here.

[00:07:24]
>> Brian Holt: Const, text, setText from = useState markdownContent. So this is the initial state, right, then we're gonna allow our users to edit it. Const, time, setTime = useState, Date.now Line and five, and nine need a K in Markdown. What?
>> Student 1: Missed the K in Markdown?
>> Student 2: Both line five and line nine, need a K.

[00:08:03]
>> Student 1: I mean, sorry, neither one needs it.
>> Student 2: [LAUGH].
>> Student 1: But as well.
>> Brian Holt: I appreciate that, thank you. Except Dustin, I don't appreciate that. Theme, setTheme
>> Brian Holt: = useState, and we'll just green, red, yellow, something there, I don't really care, some theme. UseEffect, so what we're gonna do here, just to kind of, again, demonstrate, like a constantly changing UI, we're just gonna put a clock on the page, right?

[00:08:40]
We're gonna say const interval = setInterval,
>> Brian Holt: And we're just gonna say setTime Date.now.
>> Brian Holt: And you can decide how often you want this to run. Start with every second, sound good, something like that. If you wanna make it update a lot, you can do it every millisecond.

[00:09:16]
Depending on your laptop, it probably can go okay. Const options = text, theme, and const render you're gonna be as a function text which returns, marked parse text. What, hooks? No, I don't want hooks. Where did that come from? You might be wondering why we are doing this.

[00:09:51]
Technically, you could actually just make it like a direct pass through. One, I wanted to be more explicit, as you can see that this is taking in text and it's giving it directly to marked.parse.text. You can imagine that MarkdownPreview could be like a general-purpose component that just takes in any render function and then displays it nicely for you.

[00:10:10]
So I wanted to show you kind of like that pattern as well. Okay, so now we have all the machinery up here, let's make our markup, return div className = app, h1, this is perf with React. H2, we're gonna say Current Time is time, and we're gonna say label for theme, and then say, choose a theme.

[00:10:57]
>> Brian Holt: Okay, and I'll put a select onChange e, and then you just want to do set theme e.target.value.
>> Brian Holt: And then you just need a couple of options here, I don't really care as long as it's a valid CSS color any one of these will work, value = green.

[00:11:29]
>> Brian Holt: Green, let's just make like four of these.
>> Brian Holt: Blue, blue, yellow, yellow.
>> Brian Holt: I mean, you can get creative CSS colors like Peru, it's one of my favorites, whatever you want. I just have red here, so we'll put red.
>> Brian Holt: Okay, so that'll allow us to do that.

[00:11:59]
And then we wanna do our text area so div, className = markdown, and then we're gonna have our textarea. And in there we're gonna have className = markdown-editor and value = text and onChange = e, setText e.target.value,
>> Brian Holt: Okay, and then we'll have our MarkdownPreview just right next to it, with options =(options) and render =(render).

[00:13:03]
>> Brian Holt: Okay, that should be enough for us to capture the JANK here. So, let's run it. So I think you just did npm run dev is that what I put in here? I did okay npm run dev that'll run it on 5173, right, that's the default port for vite.

[00:13:27]
I think I said this in my intro course but that's 5 is V in Roman numerals and that's V173, so, vite that's what they did, yeah? You're gonna have a memory leak in your use effect again. This one luckily never changes pages. But you are correct that my use effect here as well you should do return, clearInterval, but thank you.

[00:13:55]
Yeah, I appreciate that. I always forget that, in case this is not obvious, I always forget this and then figure out why is this slow? That's me.
>> Brian Holt: Okay, so 5173, this one.
>> Brian Holt: So we have our entire thing here, that looks good. And you notice that this render and this render move kinda in lockstep.

[00:14:31]
>> Brian Holt: Notice it's a little delayed, right? My scrolls aren't too bad here, cuz again modern browsers and modern computers are just marvels. But if I start trying to make this re-render a lot and just be like typing, it gets bad. I'm typing quite a bit here, and it's struggling.

[00:15:02]
>> Brian Holt: All right, I'm sure you're seeing something kind of similar. And it's just not good that this clock is changing, and this is changing every single time as well. So, rendering this with that expensive render every single time. We could make this, real bad. If we come in here and say, it'll start overlapping if you make it too long.

[00:15:30]
>> Brian Holt: Trying to refresh this, let's see.
>> Brian Holt: Yeah I mean look at this, it's bad. [LAUGH] that's nauseating. Okay, let's stop, we'll keep it 100 milliseconds. It's about all I can take. Okay, hopefully you see the problem here, right? I mean, even if we weren't doing this expensive render, let's just turn that off for a second to see, or we can put the JANK DELAY like one millisecond or something like that.

[00:16:04]
Yeah, right there.
>> Brian Holt: So let's try this now, I'm sure this will actually work pretty well, right?
>> Brian Holt: It's impressive that like this is re-rendering that entire markdown file every single time, which is wild to me, right? Obviously, that's not what you'd wanna do, but you can see reacts, performance profile is still actually really good.

[00:16:33]
This is still working really well. I'm also wildly impressed by this markdown parser as well.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now