Skip to content

Commit 4cd67bb

Browse files
committed
moving content to hooks
1 parent ed8cfb8 commit 4cd67bb

File tree

8 files changed

+552
-396
lines changed

8 files changed

+552
-396
lines changed

subjects/09-Render-Optimizations/exercise.js

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,51 +15,46 @@ import "./styles.css";
1515

1616
import React from "react";
1717
import ReactDOM from "react-dom";
18-
import PropTypes from "prop-types";
19-
2018
import * as RainbowListDelegate from "./RainbowListDelegate";
2119

22-
class ListView extends React.Component {
23-
static propTypes = {
24-
numRows: PropTypes.number.isRequired,
25-
rowHeight: PropTypes.number.isRequired,
26-
renderRowAtIndex: PropTypes.func.isRequired
27-
};
20+
function ListViewItem({ children }) {
21+
return <li>{children}</li>;
22+
}
2823

24+
function ListView({ numRows, rowHeight, renderRowAtIndex }) {
2925
// TODO: What state do you need?
3026

31-
handleScroll = event => {
27+
function handleScroll(event) {
3228
// TODO: Use `event.target.scrollTop` to read the current scroll position
3329
// See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTop
34-
};
35-
36-
render() {
37-
const { numRows, rowHeight, renderRowAtIndex } = this.props;
38-
const totalHeight = numRows * rowHeight;
39-
40-
// TODO: Make these numbers closer together
41-
const startIndex = 0;
42-
const endIndex = numRows;
30+
}
4331

44-
const items = [];
32+
const totalHeight = numRows * rowHeight;
4533

46-
let index = startIndex;
47-
while (index < endIndex) {
48-
items.push(<li key={index}>{renderRowAtIndex(index)}</li>);
49-
index++;
50-
}
34+
// TODO: Make these numbers smaller (what's on the screen)
35+
// so we don't render everything, just what's in view
36+
const startIndex = 0;
37+
const endIndex = numRows;
5138

52-
return (
53-
<div
54-
style={{ height: "100vh", overflowY: "scroll" }}
55-
onScroll={this.handleScroll}
56-
>
57-
<div style={{ height: totalHeight }}>
58-
<ol>{items}</ol>
59-
</div>
60-
</div>
39+
const items = [];
40+
let index = startIndex;
41+
while (index < endIndex) {
42+
items.push(
43+
<ListViewItem key={index}>{renderRowAtIndex(index)}</ListViewItem>
6144
);
45+
index++;
6246
}
47+
48+
return (
49+
<div
50+
style={{ height: "100vh", overflowY: "scroll" }}
51+
onScroll={handleScroll}
52+
>
53+
<div style={{ height: totalHeight }}>
54+
<ol>{items}</ol>
55+
</div>
56+
</div>
57+
);
6358
}
6459

6560
ReactDOM.render(

subjects/09-Render-Optimizations/lecture.js

Lines changed: 54 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,70 @@
1-
import React from "react";
1+
import React, { useState, useRef } from "react";
22
import ReactDOM from "react-dom";
3-
import PropTypes from "prop-types";
43

5-
class TodoItem extends React.Component {
6-
state = { done: false };
7-
8-
render() {
9-
return (
10-
<li>
11-
<label>
12-
<input
13-
type="checkbox"
14-
onChange={event =>
15-
this.setState({ done: event.target.checked })
16-
}
17-
/>{" "}
18-
<strong>
19-
<span style={{ textTransform: "uppercase" }}>todo:</span>{" "}
20-
</strong>
21-
<span
22-
style={{
23-
color: "blue",
24-
textDecoration: this.state.done ? "line-through" : "none"
25-
}}
26-
>
27-
{this.props.body}
28-
</span>
29-
</label>
30-
</li>
31-
);
32-
}
4+
function TodoItem({ body }) {
5+
const [done, setDone] = useState(false);
6+
console.log("render");
7+
return (
8+
<li>
9+
<label>
10+
<input
11+
type="checkbox"
12+
onChange={event => setDone(event.target.checked)}
13+
/>{" "}
14+
<strong>
15+
<span style={{ textTransform: "uppercase" }}>todo:</span>{" "}
16+
</strong>
17+
<span
18+
style={{
19+
color: "blue",
20+
textDecoration: done ? "line-through" : "none"
21+
}}
22+
>
23+
{body}
24+
</span>
25+
</label>
26+
</li>
27+
);
3328
}
3429

35-
class TodoList extends React.Component {
36-
static propTypes = {
37-
initialLength: PropTypes.number.isRequired
38-
};
30+
TodoItem = React.memo(TodoItem);
31+
32+
function TodoList({ initialLength }) {
33+
const inputRef = useRef();
34+
35+
const initialItems = Array.from(new Array(initialLength)).map(
36+
(_, index) => ({
37+
id: index,
38+
body: `item ${index + 1}`
39+
})
40+
);
3941

40-
state = {
41-
items: Array.from(new Array(this.props.initialLength)).map(
42-
(_, index) => ({
43-
id: index,
44-
body: `item ${index + 1}`
45-
})
46-
)
47-
};
42+
const [items, setItems] = useState(initialItems);
4843

49-
handleSubmit = event => {
44+
function handleSubmit(event) {
5045
event.preventDefault();
5146

5247
const item = {
53-
id: this.state.items.length,
54-
body: event.target.elements[0].value
48+
id: items.length,
49+
body: inputRef.current.value
5550
};
5651

5752
event.target.reset();
58-
59-
this.setState({
60-
items: [item].concat(this.state.items)
61-
});
62-
};
63-
64-
render() {
65-
return (
66-
<div>
67-
<form onSubmit={this.handleSubmit}>
68-
<input ref="input" />
69-
</form>
70-
<ul>
71-
{this.state.items.map(item => (
72-
<TodoItem key={item.id} body={item.body} />
73-
))}
74-
</ul>
75-
</div>
76-
);
53+
setItems([item].concat(items));
7754
}
55+
56+
return (
57+
<div>
58+
<form onSubmit={handleSubmit}>
59+
<input ref={inputRef} />
60+
</form>
61+
<ul>
62+
{items.map(item => (
63+
<TodoItem key={item.id} body={item.body} />
64+
))}
65+
</ul>
66+
</div>
67+
);
7868
}
7969

8070
ReactDOM.render(
File renamed without changes.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
////////////////////////////////////////////////////////////////////////////////
2+
// Exercise:
3+
//
4+
// - Modify <ListView> so that it only renders the list items that are visible
5+
// in the viewport (hint: what state do you need?)
6+
// - Crank up <ListView numRows> to a huge number to test your solution!
7+
//
8+
// Got extra time?
9+
//
10+
// - Adjust the number of rows as the size of the window changes (Hint: Listen
11+
// for the window's "resize" event)
12+
// - Remember the scroll position when you refresh the page
13+
////////////////////////////////////////////////////////////////////////////////
14+
import "./styles.css";
15+
16+
import React from "react";
17+
import ReactDOM from "react-dom";
18+
import PropTypes from "prop-types";
19+
20+
import * as RainbowListDelegate from "./RainbowListDelegate";
21+
22+
class ListView extends React.Component {
23+
static propTypes = {
24+
numRows: PropTypes.number.isRequired,
25+
rowHeight: PropTypes.number.isRequired,
26+
renderRowAtIndex: PropTypes.func.isRequired
27+
};
28+
29+
state = { availableHeight: 0, scrollTop: 0 };
30+
31+
handleScroll = event => {
32+
this.setState({ scrollTop: event.target.scrollTop });
33+
};
34+
35+
componentDidMount() {
36+
this.setState({ availableHeight: this.node.clientHeight });
37+
}
38+
39+
render() {
40+
const { availableHeight, scrollTop } = this.state;
41+
const { numRows, rowHeight, renderRowAtIndex } = this.props;
42+
const totalHeight = rowHeight * numRows;
43+
44+
const startIndex = Math.floor(scrollTop / rowHeight);
45+
const endIndex = Math.min(
46+
startIndex + Math.ceil(availableHeight / rowHeight) + 1,
47+
numRows
48+
);
49+
50+
const items = [];
51+
52+
let index = startIndex;
53+
while (index < endIndex) {
54+
items.push(<li key={index}>{renderRowAtIndex(index)}</li>);
55+
index++;
56+
}
57+
58+
return (
59+
<div
60+
onScroll={this.handleScroll}
61+
style={{ height: "100vh", overflowY: "scroll" }}
62+
ref={node => (this.node = node)}
63+
>
64+
<div
65+
style={{
66+
height: totalHeight,
67+
paddingTop: startIndex * rowHeight
68+
}}
69+
>
70+
<ol>{items}</ol>
71+
</div>
72+
</div>
73+
);
74+
}
75+
}
76+
77+
ReactDOM.render(
78+
<ListView
79+
numRows={500000}
80+
rowHeight={RainbowListDelegate.rowHeight}
81+
renderRowAtIndex={RainbowListDelegate.renderRowAtIndex}
82+
/>,
83+
document.getElementById("app")
84+
);

0 commit comments

Comments
 (0)