Skip to content

Commit 8a96a1a

Browse files
committed
chapter 3
1 parent e2762ea commit 8a96a1a

File tree

1 file changed

+112
-32
lines changed

1 file changed

+112
-32
lines changed

src/App.js

Lines changed: 112 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,165 @@
11
import React, { Component } from 'react';
22
import './App.css';
33

4-
const list = [
5-
{
6-
title: 'React',
7-
url: 'https://facebook.github.io/react/',
8-
author: 'Jordan Walke',
9-
num_comments: 3,
10-
points: 4,
11-
objectID: 0,
12-
},
13-
{
14-
title: 'Redux',
15-
url: 'https://github.com/reactjs/redux',
16-
author: 'Dan Abramov, Andrew Clark',
17-
num_comments: 2,
18-
points: 5,
19-
objectID: 1,
20-
},
21-
];
22-
23-
const isSearched = (searchTerm) => (item) =>
24-
!searchTerm || item.title.toLowerCase().includes(searchTerm.toLowerCase());
4+
const DEFAULT_QUERY = 'redux';
5+
const DEFAULT_PAGE = 0;
6+
const DEFAULT_HPP = '100';
7+
8+
const PATH_BASE = 'https://hn.algolia.com/api/v1';
9+
const PATH_SEARCH = '/search';
10+
const PARAM_SEARCH = 'query=';
11+
const PARAM_PAGE = 'page=';
12+
const PARAM_HPP = 'hitsPerPage=';
2513

2614
class App extends Component {
2715
constructor(props) {
2816
super(props);
2917

3018
this.state = {
31-
list,
32-
searchTerm: '',
19+
results: null,
20+
searchKey: '',
21+
searchTerm: DEFAULT_QUERY,
3322
};
3423

24+
this.needsToSearchTopstories = this.needsToSearchTopstories.bind(this);
25+
this.setSearchTopstories = this.setSearchTopstories.bind(this);
26+
this.fetchSearchTopstories = this.fetchSearchTopstories.bind(this);
3527
this.onSearchChange = this.onSearchChange.bind(this);
28+
this.onSearchSubmit = this.onSearchSubmit.bind(this);
3629
this.onDismiss = this.onDismiss.bind(this);
3730
}
3831

32+
needsToSearchTopstories(searchTerm) {
33+
return !this.state.results[searchTerm];
34+
}
35+
36+
setSearchTopstories(result) {
37+
const { hits, page } = result;
38+
const { searchKey, results } = this.state;
39+
40+
const oldHits = results && results[searchKey]
41+
? results[searchKey].hits
42+
: [];
43+
44+
const updatedHits = [
45+
...oldHits,
46+
...hits
47+
];
48+
49+
this.setState({
50+
results: {
51+
...results,
52+
[searchKey]: { hits: updatedHits, page }
53+
}
54+
});
55+
}
56+
57+
fetchSearchTopstories(searchTerm, page) {
58+
fetch(`${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${searchTerm}&${PARAM_PAGE}${page}&${PARAM_HPP}${DEFAULT_HPP}`)
59+
.then(response => response.json())
60+
.then(result => this.setSearchTopstories(result));
61+
}
62+
63+
componentDidMount() {
64+
const { searchTerm } = this.state;
65+
this.setState({ searchKey: searchTerm });
66+
this.fetchSearchTopstories(searchTerm, DEFAULT_PAGE);
67+
}
68+
3969
onSearchChange(event) {
4070
this.setState({ searchTerm: event.target.value });
4171
}
4272

73+
onSearchSubmit(event) {
74+
const { searchTerm } = this.state;
75+
this.setState({ searchKey: searchTerm });
76+
77+
if (this.needsToSearchTopstories(searchTerm)) {
78+
this.fetchSearchTopstories(searchTerm, DEFAULT_PAGE);
79+
}
80+
81+
event.preventDefault();
82+
}
83+
4384
onDismiss(id) {
85+
const { searchKey, results } = this.state;
86+
const { hits, page } = results[searchKey];
87+
4488
const isNotId = item => item.objectID !== id;
45-
const updatedList = this.state.list.filter(isNotId);
46-
this.setState({ list: updatedList });
89+
const updatedHits = hits.filter(isNotId);
90+
91+
this.setState({
92+
results: {
93+
...results,
94+
[searchKey]: { hits: updatedHits, page }
95+
}
96+
});
4797
}
4898

4999
render() {
50-
const { searchTerm, list } = this.state;
100+
const {
101+
searchTerm,
102+
results,
103+
searchKey
104+
} = this.state;
105+
106+
const page = (
107+
results &&
108+
results[searchKey] &&
109+
results[searchKey].page
110+
) || 0;
111+
112+
const list = (
113+
results &&
114+
results[searchKey] &&
115+
results[searchKey].hits
116+
) || [];
117+
51118
return (
52119
<div className="page">
53120
<div className="interactions">
54121
<Search
55122
value={searchTerm}
56123
onChange={this.onSearchChange}
124+
onSubmit={this.onSearchSubmit}
57125
>
58126
Search
59127
</Search>
60128
</div>
61129
<Table
62130
list={list}
63-
pattern={searchTerm}
64131
onDismiss={this.onDismiss}
65132
/>
133+
<div className="interactions">
134+
<Button onClick={() => this.fetchSearchTopstories(searchKey, page + 1)}>
135+
More
136+
</Button>
137+
</div>
66138
</div>
67139
);
68140
}
69141
}
70142

71-
const Search = ({ value, onChange, children }) =>
72-
<form>
73-
{children} <input
143+
const Search = ({
144+
value,
145+
onChange,
146+
onSubmit,
147+
children
148+
}) =>
149+
<form onSubmit={onSubmit}>
150+
<input
74151
type="text"
75152
value={value}
76153
onChange={onChange}
77154
/>
155+
<button type="submit">
156+
{children}
157+
</button>
78158
</form>
79159

80-
const Table = ({ list, pattern, onDismiss }) =>
160+
const Table = ({ list, onDismiss }) =>
81161
<div className="table">
82-
{ list.filter(isSearched(pattern)).map(item =>
162+
{ list.map(item =>
83163
<div key={item.objectID} className="table-row">
84164
<span style={{ width: '40%' }}>
85165
<a href={item.url}>{item.title}</a>

0 commit comments

Comments
 (0)