Skip to content

Commit 3d3c2c7

Browse files
chantastickentcdodds
authored andcommitted
migrate: exercise 05 to kcd-workshop format
1 parent 02c5aad commit 3d3c2c7

File tree

13 files changed

+96
-112
lines changed

13 files changed

+96
-112
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# DOM Side-Effects
2+
3+
For this extra credit we're going to auto-focus on the username input if there's
4+
an error after submitting. This is a common practice for accessibility purposes
5+
(to focus on the first input that has an error after a form submission).
6+
7+
So for this exercise you're going to use `useRef`. The example above should be
8+
enough to get you working. You'll pass the ref you create to the input and then
9+
in a `useEffect` you'll call `.focus()` on the input element whenever the error
10+
is displayed.
11+

src/exercise/05.tsx renamed to exercises/05.dom-side-effects/01.problem/index.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
// DOM Side-Effects
2-
// http://localhost:3000/isolated/final/02.extra-4.tsx
3-
41
import * as React from 'react'
5-
import {useLocalStorageState} from '../utils'
2+
import * as ReactDOM from 'react-dom/client'
3+
import {useLocalStorageState} from '~/shared/utils'
64

75
function UsernameForm({
86
initialUsername = '',
@@ -100,4 +98,6 @@ function App() {
10098
)
10199
}
102100

103-
export {App}
101+
const rootEl = document.createElement('div')
102+
document.body.append(rootEl)
103+
ReactDOM.createRoot(rootEl).render(<App />)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# DOM Side-Effects

src/final/05.tsx renamed to exercises/05.dom-side-effects/01.solution/index.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
// DOM Side-Effects
2-
// http://localhost:3000/isolated/final/02.extra-4.tsx
3-
41
import * as React from 'react'
5-
import {useLocalStorageState} from '../utils'
2+
import * as ReactDOM from 'react-dom/client'
3+
import {useLocalStorageState} from '~/shared/utils'
64

75
function UsernameForm({
86
initialUsername = '',
@@ -92,4 +90,6 @@ function App() {
9290
)
9391
}
9492

95-
export {App}
93+
const rootEl = document.createElement('div')
94+
document.body.append(rootEl)
95+
ReactDOM.createRoot(rootEl).render(<App />)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Side-Effect Cleanup
2+
3+
In this extra credit we're going to use a completely different example. We're
4+
going to make a `<Tilt />` component that renders a div and uses the
5+
`vanilla-tilt` library to make it super fancy.
6+
7+
The thing is, `vanilla-tilt` works directly with DOM nodes to setup event
8+
handlers and stuff, so we need access to the DOM node. But because we're not the
9+
one calling `document.createElement` (React does) we need React to give it to
10+
us.
11+
12+
So in this exercise we're going to use a `ref` so React can give us the DOM node
13+
and then we can pass that on to `vanilla-tilt`.
14+
15+
Additionally, we'll need to clean up after ourselves if this component is
16+
unmounted. Otherwise we'll have event handlers dangling around on DOM nodes that
17+
are no longer in the document which can cause a memory leak.
18+
19+
To be clear about the memory leak, just imagine what would happen if we mount a
20+
tilt element, then unmount it (without cleaning up). Those DOM nodes hang around
21+
because the event listeners are still listening to events on them (even though
22+
they're no longer in the document). Then let's say we mount a new one and
23+
unmount that again. Now we have two sets of DOM nodes that are still in memory,
24+
but not being used. We keep doing this over and over again and eventually our
25+
computer is just keeping track of all these DOM nodes we don't need it to.
26+
That's what's called a memory leak. So it's really important we clean up after
27+
ourselves to avoid the performance problems associated with memory leaks.
28+
29+
NOTE: Because this extra credit is a completely different example, you've got
30+
another starting point file in: `src/exercise/05.extra-1.tsx`. 🐨 and 💰 will be
31+
there to help you get that working.
32+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import "/vanilla-tilt.styles.css"

src/exercise/05.extra-1.tsx renamed to exercises/05.dom-side-effects/02.problem/index.tsx

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
// DOM Side-Effects
2-
// 💯 Side-effect cleanup
3-
// http://localhost:3000/isolated/exercise/05.tsx
4-
51
import * as React from 'react'
2+
import * as ReactDOM from 'react-dom/client'
63
import VanillaTilt from 'vanilla-tilt'
74

85
function Tilt({children}: {children: React.ReactNode}) {
@@ -43,7 +40,9 @@ function App() {
4340
)
4441
}
4542

46-
export {App}
43+
const rootEl = document.createElement('div')
44+
document.body.append(rootEl)
45+
ReactDOM.createRoot(rootEl).render(<App />)
4746

4847
/*
4948
eslint
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Side-Effect Cleanup
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import "/vanilla-tilt.styles.css"

src/final/05.extra-1.tsx renamed to exercises/05.dom-side-effects/02.solution/index.tsx

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
// DOM Side-Effects
2-
// 💯 Side-effect cleanup
3-
// http://localhost:3000/isolated/final/05.tsx
4-
51
import * as React from 'react'
2+
import * as ReactDOM from 'react-dom/client'
63
import VanillaTilt from 'vanilla-tilt'
74

85
interface HTMLVanillaTiltElement extends HTMLDivElement {
@@ -40,4 +37,6 @@ function App() {
4037
)
4138
}
4239

43-
export {App}
40+
const rootEl = document.createElement('div')
41+
document.body.append(rootEl)
42+
ReactDOM.createRoot(rootEl).render(<App />)
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
# DOM Side-Effects
22

3-
## 📝 Your Notes
4-
5-
Elaborate on your learnings here in `src/exercise/05.md`
6-
7-
## Background
8-
93
Often when working with React you'll need to interact with the DOM directly. You
104
may need to use a vanilla-js (non-framework-specific) library that needs to
115
interact with directly with the DOM. Often to make a UI accessible you need to
@@ -69,57 +63,3 @@ state if you're unsure and then move to a ref if you decide you don't want a
6963
rerender when it's updated. We'll dive deeper into non-DOM refs in future
7064
workshops.
7165

72-
## Exercise
73-
74-
Production deploys:
75-
76-
- [Exercise](https://react-hooks-next.netlify.app/isolated/exercise/05.tsx)
77-
- [Final](https://react-hooks-next.netlify.app/isolated/final/05.tsx)
78-
79-
For this extra credit we're going to auto-focus on the username input if there's
80-
an error after submitting. This is a common practice for accessibility purposes
81-
(to focus on the first input that has an error after a form submission).
82-
83-
So for this exercise you're going to use `useRef`. The example above should be
84-
enough to get you working. You'll pass the ref you create to the input and then
85-
in a `useEffect` you'll call `.focus()` on the input element whenever the error
86-
is displayed.
87-
88-
## Extra Credit
89-
90-
### 1. 💯 Side-effect cleanup
91-
92-
In this extra credit we're going to use a completely different example. We're
93-
going to make a `<Tilt />` component that renders a div and uses the
94-
`vanilla-tilt` library to make it super fancy.
95-
96-
The thing is, `vanilla-tilt` works directly with DOM nodes to setup event
97-
handlers and stuff, so we need access to the DOM node. But because we're not the
98-
one calling `document.createElement` (React does) we need React to give it to
99-
us.
100-
101-
So in this exercise we're going to use a `ref` so React can give us the DOM node
102-
and then we can pass that on to `vanilla-tilt`.
103-
104-
Additionally, we'll need to clean up after ourselves if this component is
105-
unmounted. Otherwise we'll have event handlers dangling around on DOM nodes that
106-
are no longer in the document which can cause a memory leak.
107-
108-
To be clear about the memory leak, just imagine what would happen if we mount a
109-
tilt element, then unmount it (without cleaning up). Those DOM nodes hang around
110-
because the event listeners are still listening to events on them (even though
111-
they're no longer in the document). Then let's say we mount a new one and
112-
unmount that again. Now we have two sets of DOM nodes that are still in memory,
113-
but not being used. We keep doing this over and over again and eventually our
114-
computer is just keeping track of all these DOM nodes we don't need it to.
115-
That's what's called a memory leak. So it's really important we clean up after
116-
ourselves to avoid the performance problems associated with memory leaks.
117-
118-
NOTE: Because this extra credit is a completely different example, you've got
119-
another starting point file in: `src/exercise/05.extra-1.tsx`. 🐨 and 💰 will be
120-
there to help you get that working.
121-
122-
## 🦉 Feedback
123-
124-
Fill out
125-
[the feedback form](https://ws.kcd.im/?ws=React%20Hooks%20%F0%9F%8E%A3&e=05%3A%20useRef%20and%20useEffect%3A%20DOM%20interaction&em=).

public/vanilla-tilt.styles.css

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
Taken from the vanilla-tilt.js demo site:
3+
https://micku7zu.github.io/vanilla-tilt.js/index.html
4+
*/
5+
.tilt-root {
6+
height: 150px;
7+
background-color: red;
8+
width: 200px;
9+
background-image: -webkit-linear-gradient(315deg, #ff00ba 0%, #fae713 100%);
10+
background-image: linear-gradient(135deg, #ff00ba 0%, #fae713 100%);
11+
transform-style: preserve-3d;
12+
will-change: transform;
13+
transform: perspective(1000px) rotateX(0deg) rotateY(0deg) scale3d(1, 1, 1);
14+
}
15+
.tilt-child {
16+
position: absolute;
17+
width: 50%;
18+
height: 50%;
19+
top: 50%;
20+
left: 50%;
21+
transform: translateZ(30px) translateX(-50%) translateY(-50%);
22+
box-shadow: 0 0 50px 0 rgba(51, 51, 51, 0.3);
23+
background-color: white;
24+
}
25+
.totally-centered {
26+
width: 100%;
27+
height: 100%;
28+
display: flex;
29+
justify-content: center;
30+
align-items: center;
31+
}

src/styles.css

-32
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,6 @@
22
color: red;
33
}
44

5-
/*
6-
Taken from the vanilla-tilt.js demo site:
7-
https://micku7zu.github.io/vanilla-tilt.js/index.html
8-
*/
9-
.tilt-root {
10-
height: 150px;
11-
background-color: red;
12-
width: 200px;
13-
background-image: -webkit-linear-gradient(315deg, #ff00ba 0%, #fae713 100%);
14-
background-image: linear-gradient(135deg, #ff00ba 0%, #fae713 100%);
15-
transform-style: preserve-3d;
16-
will-change: transform;
17-
transform: perspective(1000px) rotateX(0deg) rotateY(0deg) scale3d(1, 1, 1);
18-
}
19-
.tilt-child {
20-
position: absolute;
21-
width: 50%;
22-
height: 50%;
23-
top: 50%;
24-
left: 50%;
25-
transform: translateZ(30px) translateX(-50%) translateY(-50%);
26-
box-shadow: 0 0 50px 0 rgba(51, 51, 51, 0.3);
27-
background-color: white;
28-
}
29-
.totally-centered {
30-
width: 100%;
31-
height: 100%;
32-
display: flex;
33-
justify-content: center;
34-
align-items: center;
35-
}
36-
375
/* For exercise 6, we're handling errors with an error boundary */
386
body[class*='6'] :not(.render-container) > iframe,
397
body[class*='6'] > iframe {

0 commit comments

Comments
 (0)