Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/optimize media #826

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/VideoAsGif.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use client"
import { useEffect, useState } from "react";

export function VideoAsGif(props) {
const {src, ariaLabel} = props
const [mounted, setMounted] = useState(false)
useEffect(()=>{
setMounted(true)
}, [])

if(!mounted){
return null
}
return <video className="mb-5" src={src} muted autoPlay loop playsInline preload="auto" aria-label={ariaLabel}></video>

}
2 changes: 2 additions & 0 deletions app/[slug]/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import rehypePrettyCode from "rehype-pretty-code";
import { remarkMdxEvalCodeBlock } from "./mdx.js";
import overnight from "overnight/themes/Overnight-Slumber.json";
import "./markdown.css";
import { VideoAsGif } from "../VideoAsGif.js";

overnight.colors["editor.background"] = "var(--code-bg)";

Expand Down Expand Up @@ -53,6 +54,7 @@ export default async function PostPage({ params }) {
source={content}
components={{
a: Link,
VideoAsGif: VideoAsGif,
...postComponents,
}}
options={{
Expand Down
Binary file removed public/a-complete-guide-to-useeffect/counter.gif
Binary file not shown.
Binary file added public/a-complete-guide-to-useeffect/counter.mp4
Binary file not shown.
Binary file removed public/a-complete-guide-to-useeffect/deja_vu.gif
Binary file not shown.
Binary file added public/a-complete-guide-to-useeffect/deja_vu.mp4
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
47 changes: 35 additions & 12 deletions public/a-complete-guide-to-useeffect/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ To *see* the answers, we need to take a step back. The goal of this article isn

>“Unlearn what you have learned.” — Yoda

![Yoda sniffing the air. Caption: “I smell bacon.”](./yoda.jpg)
![Yoda sniffing the air. Caption: “I smell bacon.”](./yoda.webp)

---

Expand Down Expand Up @@ -178,7 +178,9 @@ Let’s say I do this sequence of steps:
* **Press** “Show alert”
* **Increment** it to 5 before the timeout fires

![Counter demo](./counter.gif)

<VideoAsGif src="./counter.mp4" ariaLabel="Counter Demo"/>


What do you expect the alert to show? Will it show 5 — which is the counter state at the time of the alert? Or will it show 3 — the state when I clicked?

Expand Down Expand Up @@ -465,7 +467,9 @@ If I click several times with a small delay, what is the log going to look like?
You might think this is a gotcha and the end result is unintuitive. It’s not! We’re going to see a sequence of logs — each one belonging to a particular render and thus with its own `count` value. You can [try it yourself](https://codesandbox.io/s/lyx20m1ol):


![Screen recording of 1, 2, 3, 4, 5 logged in order](./timeout_counter.gif)

<VideoAsGif src="./timeout_counter.mp4" ariaLabel="Screen recording of 1, 2, 3, 4, 5 logged in order"/>


You may think: “Of course that’s how it works! How else could it work?”

Expand All @@ -481,7 +485,9 @@ Well, that’s not how `this.state` works in classes. It’s easy to make the mi

However, `this.state.count` always points at the *latest* count rather than the one belonging to a particular render. So you’ll see `5` logged each time instead:

![Screen recording of 5, 5, 5, 5, 5 logged in order](./timeout_counter_class.gif)

<VideoAsGif src="./timeout_counter_class.mp4" ariaLabel="Screen recording of 5, 5, 5, 5, 5 logged in order"/>


I think it’s ironic that Hooks rely so much on JavaScript closures, and yet it’s the class implementation that suffers from [the canonical wrong-value-in-a-timeout confusion](https://wsvincent.com/javascript-closure-settimeout-for-loop/) that’s often associated with closures. This is because the actual source of the confusion in this example is the mutation (React mutates `this.state` in classes to point to the latest state) and not closures themselves.

Expand Down Expand Up @@ -540,7 +546,9 @@ function Example() {
// ...
```

![Screen recording of 5, 5, 5, 5, 5 logged in order](./timeout_counter_refs.gif)

<VideoAsGif src="./timeout_counter_refs.mp4" ariaLabel="Screen recording of 5, 5, 5, 5, 5 logged in order"/>


It might seem quirky to mutate something in React. However, this is exactly how React itself reassigns `this.state` in classes. Unlike with captured props and state, you don’t have any guarantees that reading `latestCount.current` would give you the same value in any particular callback. By definition, you can mutate it any time. This is why it’s not a default, and you have to opt into that.

Expand Down Expand Up @@ -580,7 +588,9 @@ You might be wondering: but how can the cleanup of the previous effect still “

We’ve been here before... 🤔

![Deja vu (cat scene from the Matrix movie)](./deja_vu.gif)

<VideoAsGif src="./deja_vu.mp4" ariaLabel="Deja vu (cat scene from the Matrix movie)"/>


Quoting the previous section:

Expand Down Expand Up @@ -802,7 +812,9 @@ If deps contain every value used by the effect, React knows when to re-run it:
}, [name]);
```

![Diagram of effects replacing one another](./deps-compare-correct.gif)

<VideoAsGif src="./deps-compare-correct.mp4" ariaLabel="Diagram of effects replacing one another"/>


*(Dependencies are different, so we re-run the effect.)*

Expand All @@ -814,7 +826,9 @@ But if we specified `[]` for this effect, the new effect function wouldn’t run
}, []); // Wrong: name is missing in deps
```

![Diagram of effects replacing one another](./deps-compare-wrong.gif)

<VideoAsGif src="./deps-compare-wrong.mp4" ariaLabel="Diagram of effects replacing one another"/>


*(Dependencies are equal, so we skip the effect.)*

Expand Down Expand Up @@ -897,7 +911,9 @@ Our effect uses `count` — a value inside the component (but outside the effect

Therefore, specifying `[]` as a dependency will create a bug. React will compare the dependencies, and skip updating this effect:

![Diagram of stale interval closure](./interval-wrong.gif)

<VideoAsGif src="./interval-wrong.mp4" ariaLabel="Diagram of stale interval closure"/>


*(Dependencies are equal, so we skip the effect.)*

Expand Down Expand Up @@ -956,7 +972,9 @@ function Counter() {

That would [fix the problem](https://codesandbox.io/s/0x0mnlyq8l) but our interval would be cleared and set again whenever the `count` changes. That may be undesirable:

![Diagram of interval that re-subscribes](./interval-rightish.gif)

<VideoAsGif src="./interval-rightish.mp4" ariaLabel="Diagram of interval that re-subscribes"/>


*(Dependencies are different, so we re-run the effect.)*

Expand Down Expand Up @@ -998,7 +1016,9 @@ That’s exactly what `setCount(c => c + 1)` does. You can think of it as “sen

**Note that we actually _did the work_ to remove the dependency. We didn’t cheat. Our effect doesn’t read the `counter` value from the render scope anymore:**

![Diagram of interval that works](./interval-right.gif)

<VideoAsGif src="./interval-right.mp4" ariaLabel="Diagram of interval that works"/>


*(Dependencies are equal, so we skip the effect.)*

Expand Down Expand Up @@ -1266,7 +1286,10 @@ By adding this dependency, we’re not just “appeasing React”. It *makes sen

Thanks to the `exhaustive-deps` lint rule from the `eslint-plugin-react-hooks` plugin, you can [analyze the effects as you type in your editor](https://github.com/facebook/react/issues/14920) and receive suggestions about which dependencies are missing. In other words, a machine can tell you which data flow changes aren’t handled correctly by a component.

![Lint rule gif](./exhaustive-deps.gif)

<VideoAsGif src="./exhaustive-deps.mp4" ariaLabel="Lint rule"/>



Pretty sweet.

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed public/a-complete-guide-to-useeffect/yoda.jpg
Binary file not shown.
Binary file added public/a-complete-guide-to-useeffect/yoda.webp
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion public/algebraic-effects-for-the-rest-of-us/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ My first attempts to figure out what they are or why I should care about them we

But my colleague Sebastian [kept](https://mobile.twitter.com/sebmarkbage/status/763792452289343490) [referring](https://mobile.twitter.com/sebmarkbage/status/776883429400915968) [to](https://mobile.twitter.com/sebmarkbage/status/776840575207116800) [them](https://mobile.twitter.com/sebmarkbage/status/969279885276454912) as a mental model for some things we do inside of React. (Sebastian works on the React team and came up with quite a few ideas, including Hooks and Suspense.) At some point, it became a running joke on the React team, with many of our conversations ending with:

!["Algebraic Effects" caption on the "Ancient Aliens" guy meme](./effects.jpg)
!["Algebraic Effects" caption on the "Ancient Aliens" guy meme](./effects.webp)

It turned out that algebraic effects are a cool concept and not as scary as I thought from those pdfs. **If you’re just using React, you don’t need to know anything about them — but if you’re feeling curious, like I was, read on.**

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class ProfilePage extends React.Component {

It is common to think these two snippets of code are equivalent. People often freely refactor between these patterns without noticing their implications:

![Spot the difference between two versions](./wtf.gif)
<VideoAsGif src="./wtf.mp4" ariaLabel="Spot the difference between two versions"/>

**However, these two snippets of code are subtly different.** Take a good look at them. Do you see the difference yet? Personally, it took me a while to see this.

Expand Down Expand Up @@ -97,7 +97,7 @@ You will notice a peculiar difference:

* With the above `ProfilePage` **class**, it would alert `'Followed Sophie'`:

![Demonstration of the steps](./bug.gif)
<VideoAsGif src="./bug.mp4" ariaLabel="Demonstration of the steps"/>

---

Expand Down Expand Up @@ -214,7 +214,7 @@ class ProfilePage extends React.Component {

**You’ve “captured” props at the time of render:**

![Capturing Pokemon](./pokemon.gif)
<VideoAsGif src="./pokemon.mp4" ariaLabel="Capturing Pokemon"/>

This way any code inside it (including `showMessage`) is guaranteed to see the props for this particular render. React doesn’t “move our cheese” anymore.

Expand Down Expand Up @@ -266,7 +266,7 @@ When the parent component renders `ProfilePage` with different props, React will

This is why, in the function version of [this demo](https://codesandbox.io/s/pjqnl16lm7), clicking Follow on Sophie’s profile and then changing selection to Sunil would alert `'Followed Sophie'`:

![Demo of correct behavior](./fix.gif)
<VideoAsGif src="./fix.mp4" ariaLabel="Demo of correct behavior"/>

This behavior is correct. *(Although you might want to [follow Sunil](https://mobile.twitter.com/threepointone) too!)*

Expand Down Expand Up @@ -397,6 +397,6 @@ Functions are no exception to this rule. It will take some time for this to be c

React functions always capture their values — and now we know why.

![Smiling Pikachu](./pikachu.gif)
<VideoAsGif src="./pikachu.mp4" ariaLabel="Smiling Pikachu"/>

They’re a whole different Pokémon.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion public/how-does-the-development-mode-work/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ That’s bad because it makes the website load and run slower.

In the last two years, the situation has significantly improved. For example, webpack added a simple `mode` option instead of manually configuring the `process.env.NODE_ENV` replacement. React DevTools also now displays a red icon on sites with development mode, making it easy to spot and even [report](https://mobile.twitter.com/BestBuySupport/status/1027195363713736704).

![Development mode warning in React DevTools](devmode.png)
![Development mode warning in React DevTools](devmode.webp)

Opinionated setups like Create React App, Next/Nuxt, Vue CLI, Gatsby, and others make it even harder to mess up by separating the development builds and production builds into two separate commands. (For example, `npm start` and `npm run build`.) Typically, only a production build can be deployed, so the developer can’t make this mistake anymore.

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ I’ll illustrate this point with a concrete example.

Let’s say we want the interval delay to be adjustable:

![Counter with an input that adjusts the interval delay](./counter_delay.gif)
<VideoAsGif src="./counter_delay.mp4" ariaLabel="Counter with an input that adjusts the interval delay"/>

While you wouldn’t necessarily control the delay with an *input*, adjusting it dynamically can be useful — for example, to poll for some AJAX updates less often while the user has switched to a different tab.

Expand Down Expand Up @@ -620,7 +620,7 @@ This `useInterval()` Hook is really fun to play with. When the side effects are

**For example, we can have a `delay` of one interval be controlled by another:**

![Counter that automatically speeds up](./counter_inception.gif)
<VideoAsGif src="./counter_inception.mp4" ariaLabel="Counter that automatically speeds up"/>

```jsx {10-15}
function Counter() {
Expand Down
Binary file not shown.
Binary file not shown.
4 changes: 2 additions & 2 deletions public/preparing-for-tech-talk-part-1-motivation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Combining these two internal motivations gives me a recipe for a personally sati

That is my formula. Yours might be different — think about it! Which talks made you feel in a special way? What are the structural similarities between them? (We’ll discuss the talk structure more in the next posts in this series.)

![Luna Lovegood invoking a Patronus Charm. Image © 2007 Warner Bros. Ent](./patronus.jpg)
![Luna Lovegood invoking a Patronus Charm. Image © 2007 Warner Bros. Ent](./patronus.webp)

Giving a talk that’s aligned with your motivations is helpful in several ways:

Expand All @@ -73,7 +73,7 @@ For me, a talk is just a way to generalize those conversations and make them one

So if you want to give a great talk, *talking* to people is a good way to start.

![Hermione Granger making a potion. Vials have text imposed on top: "motivations" and "conversations". Cauldron is a metaphor for your talk. Image © 2001 Warner Bros. Ent](./cauldron.jpg)
![Hermione Granger making a potion. Vials have text imposed on top: "motivations" and "conversations". Cauldron is a metaphor for your talk. Image © 2001 Warner Bros. Ent](./cauldron.webp)

---

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Diff not rendered.
Binary file not shown.
Diff not rendered.
Binary file not shown.
Diff not rendered.
Binary file not shown.
Diff not rendered.
Binary file not shown.
Diff not rendered.
Binary file not shown.
Diff not rendered.
Binary file not shown.
10 changes: 5 additions & 5 deletions public/preparing-for-tech-talk-part-2-what-why-and-how/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ That movie is about putting ideas into other people’s heads while they sleep.

**What is the one thing that you want people to take away from your talk?** I try to formulate it as a sentence early on. This idea shouldn’t be longer than a dozen words. People will forget most of what you say so you need to pick carefully *what* you want to stick. It’s the seed you want to plant in their heads.

![Spinning top from the Inception movie](./totem.jpg)
![Spinning top from the Inception movie](./totem.webp)

For example, here’s the core ideas of my talks.

Expand All @@ -47,7 +47,7 @@ I don’t always explicitly *say* the central idea out loud or write it on a sli

An idea is the **“What”** of my talk. But there is also **“How”** and **“Why”**:

![Pyramid: “How” is on top of “What”. “What” is on top of “Why”.](./how-what-why.png)
![Pyramid: “How” is on top of “What”. “What” is on top of “Why”.](./how-what-why.webp)

**“How”** is my method for delivering the idea to the audience. Personally, I prefer live demos, but there are many things that can work. I will talk more about “How” in the later blog posts in this series.

Expand Down Expand Up @@ -83,16 +83,16 @@ But there must be a [reason](/preparing-for-tech-talk-part-1-motivation/) you ge

Here’s the example “What”, “Why”, and “How” from my talks.

<a href="https://www.youtube.com/watch?v=xsSnOQynTHs" target="_blank">![How: “Live demo”. What: “Functional principles improve the developer experience”. Why: “Create your own tools to make programming fun”.](how-what-why-hot-reloading.png)</a>
<a href="https://www.youtube.com/watch?v=xsSnOQynTHs" target="_blank">![How: “Live demo”. What: “Functional principles improve the developer experience”. Why: “Create your own tools to make programming fun”.](how-what-why-hot-reloading.webp)</a>

*(The above pyramid is for [Hot reloading with time travel](https://www.youtube.com/watch?v=xsSnOQynTHs))*


<a href="https://www.youtube.com/watch?v=nLF0n9SACd4" target="_blank">![How: “Live demo”. What: “Waiting for CPU and IO has a unified solution”. Why: “React cares about both user and developer experience”.](how-what-why-beyond-react-16.png)</a>
<a href="https://www.youtube.com/watch?v=nLF0n9SACd4" target="_blank">![How: “Live demo”. What: “Waiting for CPU and IO has a unified solution”. Why: “React cares about both user and developer experience”.](how-what-why-beyond-react-16.webp)</a>

*(The above pyramid is for [Beyond React 16](https://www.youtube.com/watch?v=nLF0n9SACd4))*

<a href="https://www.youtube.com/watch?v=dpw9EHDh2bM" target="_blank">![How: “Live demo”. What: “Hooks make stateful logic reusable. Why: “Hooks reveal the true nature of React”.](how-what-why-introducing-hooks.png)</a>
<a href="https://www.youtube.com/watch?v=dpw9EHDh2bM" target="_blank">![How: “Live demo”. What: “Hooks make stateful logic reusable. Why: “Hooks reveal the true nature of React”.](how-what-why-introducing-hooks.webp)</a>

*(The above pyramid is for [Introducing Hooks](https://www.youtube.com/watch?v=dpw9EHDh2bM))*

Expand Down
Diff not rendered.
Binary file not shown.
2 changes: 1 addition & 1 deletion public/react-as-a-ui-runtime/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ cta: 'react'

Most tutorials introduce React as a UI library. This makes sense because React *is* a UI library. That’s literally what the tagline says!

![React homepage screenshot: "A JavaScript library for building user interfaces"](./react.png)
![React homepage screenshot: "A JavaScript library for building user interfaces"](./react.webp)

I’ve written about the challenges of creating [user interfaces](/the-elements-of-ui-engineering/) before. But this post talks about React in a different way — more as a [programming runtime](https://en.wikipedia.org/wiki/Runtime_system).

Expand Down
Binary file removed public/react-as-a-ui-runtime/react.png
Diff not rendered.
Binary file added public/react-as-a-ui-runtime/react.webp
Binary file not shown.
2 changes: 1 addition & 1 deletion public/the-wet-codebase/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ But as any Phish fan can tell you, [wasting time](https://www.youtube.com/watch?

A year ago, I gave a conference talk, and I want to share it today with those of you who haven’t watched it. This talk isn’t about React, or even JavaScript.

<a target="_blank" href="https://www.deconstructconf.com/2019/dan-abramov-the-wet-codebase">![Slide from the talk](./wet_codebase.png)</a>
<a target="_blank" href="https://www.deconstructconf.com/2019/dan-abramov-the-wet-codebase">![Slide from the talk](./wet_codebase.webp)</a>

**[Watch: The Wet Codebase](https://www.deconstructconf.com/2019/dan-abramov-the-wet-codebase)** *(includes transcript)*

Expand Down
Binary file removed public/the-wet-codebase/wet_codebase.png
Diff not rendered.
Binary file added public/the-wet-codebase/wet_codebase.webp
Binary file not shown.
Binary file removed public/why-do-hooks-rely-on-call-order/hooks-hn1.png
Diff not rendered.
Binary file not shown.
Binary file removed public/why-do-hooks-rely-on-call-order/hooks-hn2.png
Diff not rendered.
Binary file not shown.
4 changes: 2 additions & 2 deletions public/why-do-hooks-rely-on-call-order/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ If you’d like to understand what Hooks are and what problems they solve, check

Chances are you won’t like Hooks at first:

![Negative HN comment](./hooks-hn1.png)
![Negative HN comment](./hooks-hn1.webp)

They’re like a music record that grows on you only after a few good listens:

![Positive HN comment from the same person four days later](./hooks-hn2.png)
![Positive HN comment from the same person four days later](./hooks-hn2.webp)

When you read the docs, don’t miss [the most important page](https://reactjs.org/docs/hooks-custom.html) about building your own Hooks! Too many people get fixated on some part of our messaging they disagree with (e.g. that learning classes is difficult) and miss the bigger picture behind Hooks. And the bigger picture is that **Hooks are like *functional mixins* that let you create and compose your own abstractions.**

Expand Down
2 changes: 1 addition & 1 deletion public/writing-resilient-components/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ Note how this array of “effect dependencies” isn’t really a new concept. I

This, in turn, lets us validate them automatically:

![Demo of exhaustive-deps lint rule](./useeffect.gif)
<VideoAsGif src="./useeffect.mp4" ariaLabel="Demo of exhaustive-deps lint rule"/>

*(This is a demo of the new recommended `exhaustive-deps` lint rule which is a part of `eslint-plugin-react-hooks`. It will soon be included in Create React App.)*

Expand Down
Binary file removed public/writing-resilient-components/useeffect.gif
Diff not rendered.
Binary file not shown.