Skip to content

Commit 3bf1940

Browse files
Finish Video
1 parent a0c374a commit 3bf1940

File tree

13 files changed

+176
-3
lines changed

13 files changed

+176
-3
lines changed

src/13-useEventListener/useEventListener.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export default function useEventListener(
1212
}, [callback])
1313

1414
useEffect(() => {
15+
if (element == null) return
1516
const handler = e => callbackRef.current(e)
1617
element.addEventListener(eventType, handler)
1718

src/14-useOnScreen/useOnScreen.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ export default function useOnScreen(ref, rootMargin = "0px") {
44
const [isVisible, setIsVisible] = useState(false)
55

66
useEffect(() => {
7-
console.log(ref.current)
87
if (ref.current == null) return
98
const observer = new IntersectionObserver(
109
([entry]) => setIsVisible(entry.isIntersecting),
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import useMediaQuery from "./useMediaQuery"
2+
3+
export default function MediaQueryComponent() {
4+
const isLarge = useMediaQuery("(min-width: 200px)")
5+
6+
return <div>Large: {isLarge.toString()}</div>
7+
}

src/16-useMediaQuery/useMediaQuery.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { useState, useEffect } from "react"
2+
import useEventListener from "../13-useEventListener/useEventListener"
3+
4+
export default function useMediaQuery(mediaQuery) {
5+
const [isMatch, setIsMatch] = useState(false)
6+
const [mediaQueryList, setMediaQueryList] = useState(null)
7+
8+
useEffect(() => {
9+
const list = window.matchMedia(mediaQuery)
10+
setMediaQueryList(list)
11+
setIsMatch(list.matches)
12+
}, [mediaQuery])
13+
14+
useEventListener("change", e => setIsMatch(e.matches), mediaQueryList)
15+
16+
return isMatch
17+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { useRef } from "react"
2+
import useGeolocation from "./useGeolocation"
3+
4+
export default function GeolocationComponent() {
5+
const ref = useRef()
6+
const {
7+
loading,
8+
error,
9+
data: { latitude, longitude },
10+
} = useGeolocation(ref)
11+
12+
return (
13+
<>
14+
<div>Loading: {loading.toString()}</div>
15+
<div>Error: {error?.message}</div>
16+
<div>
17+
{latitude} x {longitude}
18+
</div>
19+
</>
20+
)
21+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { useState, useEffect } from "react"
2+
3+
export default function useGeolocation(options) {
4+
const [loading, setLoading] = useState(true)
5+
const [error, setError] = useState()
6+
const [data, setData] = useState({})
7+
8+
useEffect(() => {
9+
const successHandler = e => {
10+
setLoading(false)
11+
setError(null)
12+
setData(e.coords)
13+
}
14+
const errorHandler = e => {
15+
setError(e)
16+
setLoading(false)
17+
}
18+
navigator.geolocation.getCurrentPosition(
19+
successHandler,
20+
errorHandler,
21+
options
22+
)
23+
const id = navigator.geolocation.watchPosition(
24+
successHandler,
25+
errorHandler,
26+
options
27+
)
28+
return () => navigator.geolocation.clearWatch(id)
29+
}, [options])
30+
31+
return { loading, error, data }
32+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import useStateWithValidation from "./useStateWithValidation"
2+
3+
export default function StateWithValidationComponent() {
4+
const [username, setUsername, isValid] = useStateWithValidation(
5+
name => name.length > 5,
6+
""
7+
)
8+
9+
return (
10+
<>
11+
<div>Valid: {isValid.toString()}</div>
12+
<input
13+
type="text"
14+
value={username}
15+
onChange={e => setUsername(e.target.value)}
16+
/>
17+
</>
18+
)
19+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { useState, useCallback } from "react"
2+
3+
export default function useStateWithValidation(validationFunc, initialValue) {
4+
const [state, setState] = useState(initialValue)
5+
const [isValid, setIsValid] = useState(() => validationFunc(state))
6+
7+
const onChange = useCallback(
8+
nextState => {
9+
const value =
10+
typeof nextState === "function" ? nextState(state) : nextState
11+
setState(value)
12+
setIsValid(validationFunc(value))
13+
},
14+
[validationFunc]
15+
)
16+
17+
return [state, onChange, isValid]
18+
}

src/19-useSize/SizeComponent.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { useRef } from "react"
2+
import useSize from "./useSize"
3+
4+
export default function SizeComponent() {
5+
const ref = useRef()
6+
const size = useSize(ref)
7+
8+
return (
9+
<>
10+
<div>{JSON.stringify(size)}</div>
11+
<textarea ref={ref}></textarea>
12+
</>
13+
)
14+
}

src/19-useSize/useSize.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { useState } from "react"
2+
import { useEffect } from "react/cjs/react.development"
3+
4+
export default function useSize(ref) {
5+
const [size, setSize] = useState({})
6+
7+
useEffect(() => {
8+
if (ref.current == null) return
9+
const observer = new ResizeObserver(([entry]) => setSize(entry.contentRect))
10+
observer.observe(ref.current)
11+
return () => observer.disconnect()
12+
}, [])
13+
14+
return size
15+
}

0 commit comments

Comments
 (0)