Skip to content

Commit 909aac7

Browse files
committed
finish
1 parent a3fef41 commit 909aac7

File tree

8 files changed

+129
-56
lines changed

8 files changed

+129
-56
lines changed

.travis.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
language: node_js
2+
3+
node_js:
4+
- stable
5+
6+
install:
7+
- npm install
8+
9+
script:
10+
- npm test

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
[![Build Status](https://travis-ci.org/the-road-to-learn-react/react-rxjs-state-example.svg?branch=master)](https://travis-ci.org/the-road-to-learn-react/react-rxjs-state-example) [![Slack](https://slack-the-road-to-learn-react.wieruch.com/badge.svg)](https://slack-the-road-to-learn-react.wieruch.com/)
44

5+
Showcasing how RxJS can work in React. [Read more about it.](https://www.robinwieruch.de/react-rxjs-state-management-tutorial/)
6+
57
## Installation
68

79
* `git clone git@github.com:the-road-to-learn-react/react-rxjs-state-example.git`

package-lock.json

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {
6+
"axios": "^0.18.0",
67
"react": "^16.4.2",
78
"react-dom": "^16.4.2",
89
"react-scripts": "1.1.4",

src/App.js

Lines changed: 75 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,92 @@
11
import React from 'react';
2+
import axios from 'axios';
3+
import { BehaviorSubject } from 'rxjs/index';
4+
import { combineLatest, timer } from 'rxjs';
5+
import { flatMap, map, debounce, filter } from 'rxjs/operators';
26

3-
import { selectedCurrency$, CURRENCIES } from './state';
4-
import connect from './connect';
7+
import withObservableStream from './withObservableStream';
58

6-
const TradingPairs = ({ currency, actions }) => (
9+
const SUBJECT = {
10+
POPULARITY: 'search',
11+
DATE: 'search_by_date',
12+
};
13+
14+
const App = ({
15+
subject,
16+
query,
17+
stories,
18+
onSelectSubject,
19+
onChangeInput,
20+
}) => (
721
<div>
8-
<h1>Trading Pair</h1>
9-
<p>{currency}</p>
22+
<h1>Hacker News with React and Rx.js</h1>
1023

1124
<div>
12-
{Object.values(CURRENCIES).map(currency => (
25+
{Object.values(SUBJECT).map(subject => (
1326
<button
14-
key={currency}
15-
onClick={() => actions.onSelectCurrency({ currency })}
27+
key={subject}
28+
onClick={() => onSelectSubject(subject)}
1629
type="button"
1730
>
18-
{currency}
31+
{subject}
1932
</button>
2033
))}
2134
</div>
35+
36+
<input
37+
type="text"
38+
onChange={event => onChangeInput(event.target.value)}
39+
/>
40+
41+
<p>{`http://hn.algolia.com/api/v1/${subject}?query=${query}`}</p>
42+
43+
<ul>
44+
{stories.map(story => (
45+
<li key={story.objectID}>
46+
<a href={story.url || story.story_url}>
47+
{story.title || story.story_title}
48+
</a>
49+
</li>
50+
))}
51+
</ul>
2252
</div>
2353
);
2454

25-
const TradingPairsConnected = connect(
26-
selectedCurrency$,
27-
{
28-
onSelectCurrency: selectedCurrency$.next.bind(selectedCurrency$),
29-
},
30-
)(TradingPairs);
55+
const subject$ = new BehaviorSubject(SUBJECT.POPULARITY);
56+
const query$ = new BehaviorSubject('');
3157

32-
const App = () => <TradingPairsConnected />;
58+
const queryToFetch$ = query$.pipe(
59+
debounce(() => timer(1000)),
60+
filter(query => query !== ''),
61+
);
62+
63+
const fetch$ = combineLatest(subject$, queryToFetch$).pipe(
64+
flatMap(([subject, query]) =>
65+
axios(`http://hn.algolia.com/api/v1/${subject}?query=${query}`),
66+
),
67+
map(result => result.data.hits),
68+
);
3369

34-
export default App;
70+
export default withObservableStream(
71+
// observables
72+
[
73+
combineLatest(subject$, query$, (subject, query) => ({
74+
subject,
75+
query,
76+
})),
77+
combineLatest(fetch$, stories => ({
78+
stories,
79+
})),
80+
],
81+
// handler
82+
{
83+
onSelectSubject: subject => subject$.next(subject),
84+
onChangeInput: value => query$.next(value),
85+
},
86+
// initial state
87+
{
88+
subject: SUBJECT.POPULARITY,
89+
query: '',
90+
stories: [],
91+
},
92+
)(App);

src/connect.js

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/state.js

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/withObservableStream.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from 'react';
2+
3+
export default (observables, actions, initialState) => Component => {
4+
return class extends React.Component {
5+
constructor(props) {
6+
super(props);
7+
8+
this.state = { ...initialState };
9+
}
10+
11+
componentDidMount() {
12+
this.subscriptions = observables.map(observable =>
13+
observable.subscribe(newState =>
14+
this.setState({ ...newState }),
15+
),
16+
);
17+
}
18+
19+
componentWillUnmount() {
20+
this.subscriptions.forEach(subscription =>
21+
subscription.unsubscribe(),
22+
);
23+
}
24+
25+
render() {
26+
return (
27+
<Component {...this.props} {...this.state} {...actions} />
28+
);
29+
}
30+
};
31+
};

0 commit comments

Comments
 (0)