Skip to content

Commit a0eb944

Browse files
committed
Add HOC hooks solution
1 parent 16a2df2 commit a0eb944

File tree

2 files changed

+108
-77
lines changed

2 files changed

+108
-77
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
////////////////////////////////////////////////////////////////////////////////
2+
// Exercise:
3+
//
4+
// - Make the mouse-tracking logic reusable by filling in the `withMouse`
5+
// higher-order component and returning a new component that renders the
6+
// given component with a `mouse` prop
7+
//
8+
// Got extra time?
9+
//
10+
// - Make a `withCat` HOC that shows a cat chasing the mouse around the screen!
11+
////////////////////////////////////////////////////////////////////////////////
12+
import "./styles.css";
13+
14+
import React from "react";
15+
import ReactDOM from "react-dom";
16+
import PropTypes from "prop-types";
17+
18+
import { useState, useEffect, useRef } from "react";
19+
20+
function useMouse() {
21+
const [position, updatePosition] = useState({ x: 0, y: 0 });
22+
23+
function handleMouseMove(event) {
24+
updatePosition({ x: event.clientX, y: event.clientY });
25+
}
26+
27+
return { mouse: position, onMouseMove: handleMouseMove };
28+
}
29+
30+
function useCat(mouse) {
31+
const [dimensions, updateDimensions] = useState({
32+
height: 0,
33+
width: 0
34+
});
35+
const catRef = useRef();
36+
37+
useEffect(() => {
38+
updateDimensions({
39+
height: catRef.current.offsetHeight,
40+
width: catRef.current.offsetWidth
41+
});
42+
}, []);
43+
44+
const { height, width } = dimensions;
45+
const { x, y } = mouse;
46+
const style = {
47+
left: x - width / 2,
48+
top: y - height / 2
49+
};
50+
51+
return <div className="cat" style={style} ref={catRef} />;
52+
}
53+
54+
function App() {
55+
const { mouse, onMouseMove } = useMouse();
56+
const cat = useCat(mouse);
57+
58+
return (
59+
<div className="container" onMouseMove={onMouseMove}>
60+
{cat}
61+
<h1>
62+
The mouse position is ({mouse.x}, {mouse.y})
63+
</h1>
64+
</div>
65+
);
66+
}
67+
68+
ReactDOM.render(<App />, document.getElementById("app"));

subjects/08-Render-Props/solution-hooks.js

Lines changed: 40 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -28,107 +28,70 @@ import getAddressFromCoords from "./utils/getAddressFromCoords";
2828
import { useState, useEffect } from "react";
2929

3030
function useGeoPosition() {
31-
const [/* current state */ geo, /* setState */ updateGeo] = useState(
32-
/* initial state */ {
33-
coords: {
34-
latitude: null,
35-
longitude: null
36-
},
37-
error: null
38-
}
39-
);
40-
31+
const [coords, updateCoords] = useState({
32+
latitude: null,
33+
longitude: null
34+
});
35+
const [
36+
/* this.state */ error,
37+
/*this.setState*/ updateError
38+
] = useState(/*state = ...*/ null);
39+
40+
// useEffect(sideEffect, dependencies)
41+
// componentDidMount
4142
useEffect(() => {
42-
const geoId = navigator.geolocation.watchPosition(
43-
position => {
44-
updateGeo({
45-
coords: {
46-
latitude: position.coords.latitude,
47-
longitude: position.coords.longitude
48-
}
49-
});
50-
},
51-
error => {
52-
updateGeo({ error });
53-
}
54-
);
43+
const geoId = navigator.geolocation.watchPosition(position => {
44+
updateCoords({
45+
latitude: position.coords.latitude,
46+
longitude: position.coords.longitude
47+
});
48+
}, updateError);
5549

50+
// componentWillUnmount
5651
return () => {
5752
navigator.geolocation.clearWatch(geoId);
5853
};
5954
}, []);
6055

61-
return geo;
56+
return { coords, error };
6257
}
6358

64-
function useAddress(coords) {
59+
function useAddress(latitude, longitude) {
6560
const [address, updateAddress] = useState(null);
6661

67-
function refreshAddress() {
68-
updateAddress(null);
69-
70-
const { latitude, longitude } = coords;
71-
72-
if (latitude && longitude) {
73-
getAddressFromCoords(latitude, longitude).then(updateAddress);
74-
}
75-
}
76-
77-
useEffect(refreshAddress, [coords.latitude, coords.longitude]);
62+
useEffect(
63+
() => {
64+
if (latitude && longitude) {
65+
getAddressFromCoords(latitude, longitude).then(updateAddress);
66+
}
67+
},
68+
[latitude, longitude]
69+
);
7870

7971
return address;
8072
}
8173

82-
/*
83-
const [
84-
// current state
85-
geo,
86-
// setState
87-
updateGeo
88-
] = useState(
89-
// initial state
90-
{
91-
coords: {
92-
latitude: null,
93-
longitude: null
94-
},
95-
error: null
96-
}
97-
);
98-
99-
useEffect(() => {
100-
// componentDidMount and/or componentDidUpdate
101-
return () => {
102-
// componentWillUnmount
103-
}
104-
},
105-
// prop diff in componentDidUpdate
106-
[when, this, stuff, changes, run, it, again]
107-
)
108-
*/
109-
110-
function App() {
74+
function App(props) {
11175
const { coords, error } = useGeoPosition();
112-
const address = useAddress(coords);
76+
const address = useAddress(coords.latitude, coords.longitude);
11377

11478
return (
11579
<div>
11680
<h1>Geolocation</h1>
117-
11881
{error ? (
11982
<div>Error: {error.message}</div>
12083
) : (
121-
<dl>
122-
<dt>Latitude</dt>
123-
<dd>{coords.latitude || <LoadingDots />}</dd>
124-
<dt>Longitude</dt>
125-
<dd>{coords.longitude || <LoadingDots />}</dd>
126-
</dl>
84+
<div>
85+
<dl>
86+
<dt>Latitude</dt>
87+
<dd>{coords.latitude || <LoadingDots />}</dd>
88+
<dt>Longitude</dt>
89+
<dd>{coords.longitude || <LoadingDots />}</dd>
90+
</dl>
91+
92+
<marquee>{address || <LoadingDots />}</marquee>
93+
</div>
12794
)}
128-
129-
<marquee>
130-
<p>The address is {address || <LoadingDots />}</p>
131-
</marquee>
13295
</div>
13396
);
13497
}

0 commit comments

Comments
 (0)