Skip to content

Commit

Permalink
chapter 3
Browse files Browse the repository at this point in the history
  • Loading branch information
rwieruch committed Feb 14, 2018
1 parent 5b68953 commit becd9e6
Showing 1 changed file with 123 additions and 36 deletions.
159 changes: 123 additions & 36 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,85 +1,172 @@
import React, { Component } from 'react';
import './App.css';

const list = [
{
title: 'React',
url: 'https://facebook.github.io/react/',
author: 'Jordan Walke',
num_comments: 3,
points: 4,
objectID: 0,
},
{
title: 'Redux',
url: 'https://github.com/reactjs/redux',
author: 'Dan Abramov, Andrew Clark',
num_comments: 2,
points: 5,
objectID: 1,
},
];

const isSearched = searchTerm => item =>
item.title.toLowerCase().includes(searchTerm.toLowerCase());
const DEFAULT_QUERY = 'redux';
const DEFAULT_HPP = '100';

const PATH_BASE = 'https://hn.algolia.com/api/v1';
const PATH_SEARCH = '/search';
const PARAM_SEARCH = 'query=';
const PARAM_PAGE = 'page=';
const PARAM_HPP = 'hitsPerPage=';

class App extends Component {
constructor(props) {
super(props);

this.state = {
list,
searchTerm: '',
results: null,
searchKey: '',
searchTerm: DEFAULT_QUERY,
error: null,
};

this.needsToSearchTopStories = this.needsToSearchTopStories.bind(this);
this.setSearchTopStories = this.setSearchTopStories.bind(this);
this.fetchSearchTopStories = this.fetchSearchTopStories.bind(this);
this.onSearchChange = this.onSearchChange.bind(this);
this.onSearchSubmit = this.onSearchSubmit.bind(this);
this.onDismiss = this.onDismiss.bind(this);
}

needsToSearchTopStories(searchTerm) {
return !this.state.results[searchTerm];
}

setSearchTopStories(result) {
const { hits, page } = result;
const { searchKey, results } = this.state;

const oldHits = results && results[searchKey]
? results[searchKey].hits
: [];

const updatedHits = [
...oldHits,
...hits
];

this.setState({
results: {
...results,
[searchKey]: { hits: updatedHits, page }
}
});
}

fetchSearchTopStories(searchTerm, page = 0) {
fetch(`${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${searchTerm}&${PARAM_PAGE}${page}&${PARAM_HPP}${DEFAULT_HPP}`)
.then(response => response.json())
.then(result => this.setSearchTopStories(result))
.catch(error => this.setState({ error }));
}

componentDidMount() {
const { searchTerm } = this.state;
this.setState({ searchKey: searchTerm });
this.fetchSearchTopStories(searchTerm);
}

onSearchChange(event) {
this.setState({ searchTerm: event.target.value });
}

onSearchSubmit(event) {
const { searchTerm } = this.state;
this.setState({ searchKey: searchTerm });

if (this.needsToSearchTopStories(searchTerm)) {
this.fetchSearchTopStories(searchTerm);
}

event.preventDefault();
}

onDismiss(id) {
const { searchKey, results } = this.state;
const { hits, page } = results[searchKey];

const isNotId = item => item.objectID !== id;
const updatedList = this.state.list.filter(isNotId);
this.setState({ list: updatedList });
const updatedHits = hits.filter(isNotId);

this.setState({
results: {
...results,
[searchKey]: { hits: updatedHits, page }
}
});
}

render() {
const { searchTerm, list } = this.state;
const {
searchTerm,
results,
searchKey,
error
} = this.state;

const page = (
results &&
results[searchKey] &&
results[searchKey].page
) || 0;

const list = (
results &&
results[searchKey] &&
results[searchKey].hits
) || [];

return (
<div className="page">
<div className="interactions">
<Search
value={searchTerm}
onChange={this.onSearchChange}
onSubmit={this.onSearchSubmit}
>
Search
</Search>
</div>
<Table
list={list}
pattern={searchTerm}
onDismiss={this.onDismiss}
/>
{ error
? <div className="interactions">
<p>Something went wrong.</p>
</div>
: <Table
list={list}
onDismiss={this.onDismiss}
/>
}
<div className="interactions">
<Button onClick={() => this.fetchSearchTopStories(searchKey, page + 1)}>
More
</Button>
</div>
</div>
);
}
}

const Search = ({ value, onChange, children }) =>
<form>
{children} <input
const Search = ({
value,
onChange,
onSubmit,
children
}) =>
<form onSubmit={onSubmit}>
<input
type="text"
value={value}
onChange={onChange}
/>
<button type="submit">
{children}
</button>
</form>

const Table = ({ list, pattern, onDismiss }) =>
const Table = ({ list, onDismiss }) =>
<div className="table">
{list.filter(isSearched(pattern)).map(item =>
{list.map(item =>
<div key={item.objectID} className="table-row">
<span style={{ width: '40%' }}>
<a href={item.url}>{item.title}</a>
Expand Down

0 comments on commit becd9e6

Please sign in to comment.