From 93a91c759b09d28c059f035263ac6a55f7357179 Mon Sep 17 00:00:00 2001 From: "manuel.soto" Date: Sun, 28 Jul 2019 18:47:33 -0300 Subject: [PATCH 1/2] grap initial state from the observer + strong type --- package-lock.json | 178 +++++++++++++---------------------- package.json | 22 ++++- src/App.js | 93 ------------------ src/App.tsx | 125 ++++++++++++++++++++++++ src/react-app-env.d.ts | 1 + src/withObservableStream.js | 29 ------ src/withObservableStream.tsx | 54 +++++++++++ tsconfig.json | 25 +++++ 8 files changed, 285 insertions(+), 242 deletions(-) delete mode 100644 src/App.js create mode 100644 src/App.tsx create mode 100644 src/react-app-env.d.ts delete mode 100644 src/withObservableStream.js create mode 100644 src/withObservableStream.tsx create mode 100644 tsconfig.json diff --git a/package-lock.json b/package-lock.json index 769e9bb..23b705d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1902,12 +1902,35 @@ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, "axios": { - "version": "0.18.0", - "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", - "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", + "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", "requires": { - "follow-redirects": "^1.3.0", - "is-buffer": "^1.1.5" + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" + } } }, "axobject-query": { @@ -3519,11 +3542,6 @@ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" - }, "core-js-compat": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.0.1.tgz", @@ -4282,14 +4300,6 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "requires": { - "iconv-lite": "~0.4.13" - } - }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -5110,20 +5120,6 @@ "bser": "^2.0.0" } }, - "fbjs": { - "version": "0.8.17", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", - "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", - "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.18" - } - }, "figgy-pudding": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", @@ -6304,15 +6300,6 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, - "isomorphic-fetch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", - "requires": { - "node-fetch": "^1.0.1", - "whatwg-fetch": ">=0.10.0" - } - }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -7721,9 +7708,9 @@ } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, "lodash._reinterpolate": { "version": "3.0.0", @@ -8047,9 +8034,9 @@ } }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" @@ -8192,15 +8179,6 @@ "lower-case": "^1.1.1" } }, - "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } - }, "node-forge": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", @@ -9771,14 +9749,6 @@ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" }, - "promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "requires": { - "asap": "~2.0.3" - } - }, "promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -9944,14 +9914,14 @@ } }, "react": { - "version": "16.4.2", - "resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz", - "integrity": "sha512-dMv7YrbxO4y2aqnvA7f/ik9ibeLSHQJTI6TrYAenPSaQ6OXfb+Oti+oJiy8WBxgRzlKatYqtCjphTgDSCEiWFg==", + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz", + "integrity": "sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==", "requires": { - "fbjs": "^0.8.16", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.0" + "prop-types": "^15.6.2", + "scheduler": "^0.13.6" } }, "react-app-polyfill": { @@ -10073,14 +10043,14 @@ } }, "react-dom": { - "version": "16.4.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.2.tgz", - "integrity": "sha512-Usl73nQqzvmJN+89r97zmeUpQDKDlh58eX6Hbs/ERdDHzeBzWy+ENk7fsGQ+5KxArV1iOFPT46/VneklK9zoWw==", + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.6.tgz", + "integrity": "sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==", "requires": { - "fbjs": "^0.8.16", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.0" + "prop-types": "^15.6.2", + "scheduler": "^0.13.6" } }, "react-error-overlay": { @@ -10547,9 +10517,9 @@ } }, "rxjs": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.2.tgz", - "integrity": "sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", "requires": { "tslib": "^1.9.0" } @@ -10662,6 +10632,15 @@ "xmlchars": "^1.3.1" } }, + "scheduler": { + "version": "0.13.6", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", + "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -10771,9 +10750,9 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", @@ -11678,11 +11657,6 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, - "ua-parser-js": { - "version": "0.7.18", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz", - "integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA==" - }, "uglify-js": { "version": "3.4.10", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", @@ -11762,35 +11736,14 @@ } }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "uniq": { @@ -12336,11 +12289,6 @@ } } }, - "whatwg-fetch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", - "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" - }, "whatwg-mimetype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", diff --git a/package.json b/package.json index 13e7663..cf3500b 100644 --- a/package.json +++ b/package.json @@ -3,16 +3,28 @@ "version": "0.1.0", "private": true, "dependencies": { - "axios": "^0.18.0", - "react": "^16.4.2", - "react-dom": "^16.4.2", - "react-scripts": "3.0.1", - "rxjs": "^6.2.2" + "axios": "^0.18.1", + "react": "^16.8.6", + "react-dom": "^16.8.6", + "react-scripts": "3.x", + "rxjs": "^6.5.2" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] } } diff --git a/src/App.js b/src/App.js deleted file mode 100644 index ea8571b..0000000 --- a/src/App.js +++ /dev/null @@ -1,93 +0,0 @@ -import React from 'react'; -import axios from 'axios'; -import { BehaviorSubject, combineLatest, timer } from 'rxjs'; -import { flatMap, map, debounce, filter } from 'rxjs/operators'; - -import withObservableStream from './withObservableStream'; - -const SUBJECT = { - POPULARITY: 'search', - DATE: 'search_by_date', -}; - -const App = ({ - query, - subject, - stories, - onChangeQuery, - onSelectSubject, -}) => ( -
-

React with RxJS

- - onChangeQuery(event.target.value)} - /> - -
- {Object.values(SUBJECT).map(subject => ( - - ))} -
- -

- Fetching from:{' '} - {`http://hn.algolia.com/api/v1/${subject}?query=${query}`} -

- - -
-); - -const query$ = new BehaviorSubject('react'); -const subject$ = new BehaviorSubject(SUBJECT.POPULARITY); - -const queryForFetch$ = query$.pipe( - debounce(() => timer(1000)), - filter(query => query !== ''), -); - -const fetch$ = combineLatest(subject$, queryForFetch$).pipe( - flatMap(([subject, query]) => - axios(`http://hn.algolia.com/api/v1/${subject}?query=${query}`), - ), - map(result => result.data.hits), -); - -export default withObservableStream( - combineLatest( - subject$, - query$, - fetch$, - (subject, query, stories) => ({ - subject, - query, - stories, - }), - ), - { - onSelectSubject: subject => subject$.next(subject), - onChangeQuery: value => query$.next(value), - }, - { - query: 'react', - subject: SUBJECT.POPULARITY, - stories: [], - }, -)(App); diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..5a67449 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,125 @@ +import React from 'react'; +import axios from 'axios'; +import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; +import { + map, + filter, + startWith, + debounceTime, + distinctUntilChanged, + switchMap, + catchError, +} from 'rxjs/operators'; + +import withObservableStream from './withObservableStream'; + +interface Consumer { + (value: T): void; +} + +interface Story { + objectID: string; + url?: string; + story_url?: string; + title?: string; + story_title?: string; +} + +interface PropsType { + query: string; + subject: string; + stories: Array; +} + +interface TriggersType { + onChangeQuery: Consumer; + onSelectSubject: Consumer; +} + +type AppProps = TriggersType & PropsType; + +const SUBJECT = { + POPULARITY: 'search', + DATE: 'search_by_date', +}; + +const App = ({ + query, + subject, + stories, + onChangeQuery, + onSelectSubject, +}: AppProps) => ( +
+

React with RxJS

+ + onChangeQuery(event.target.value)} + /> + +
+ {Object.values(SUBJECT).map(subject => ( + + ))} +
+ +

+ Fetching from:{' '} + {`http://hn.algolia.com/api/v1/${subject}?query=${query}`} +

+ + +
+); + +const query$ = new BehaviorSubject('react'); +const subject$ = new BehaviorSubject(SUBJECT.POPULARITY); + +const queryForFetch$ = query$.pipe( + debounceTime(1000), + distinctUntilChanged(), + filter(Boolean), +); + +const fetch$ = combineLatest(subject$, queryForFetch$).pipe( + switchMap( + // discard previous requests. Response order not granted. + ([subject, query]) => + axios(`http://hn.algolia.com/api/v1/${subject}?query=${query}`), + ), + map(result => result.data.hits as Array), + startWith([]), + catchError(() => []), +); + +const state$: Observable = combineLatest( + subject$, + query$, + fetch$, + (subject, query, stories) => ({ + subject, + query, + stories, + }), +); + +export default withObservableStream(state$, { + onSelectSubject: (subject: string) => subject$.next(subject), + onChangeQuery: (value: string) => query$.next(value), +})(App); diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts new file mode 100644 index 0000000..6431bc5 --- /dev/null +++ b/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/src/withObservableStream.js b/src/withObservableStream.js deleted file mode 100644 index 6cf9c96..0000000 --- a/src/withObservableStream.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; - -export default (observable, triggers, initialState) => Component => { - return class extends React.Component { - constructor(props) { - super(props); - - this.state = { - ...initialState, - }; - } - - componentDidMount() { - this.subscription = observable.subscribe(newState => - this.setState({ ...newState }), - ); - } - - componentWillUnmount() { - this.subscription.unsubscribe(); - } - - render() { - return ( - - ); - } - }; -}; diff --git a/src/withObservableStream.tsx b/src/withObservableStream.tsx new file mode 100644 index 0000000..febe0f0 --- /dev/null +++ b/src/withObservableStream.tsx @@ -0,0 +1,54 @@ +import React, { Component } from 'react'; +import { Observable, Subscription } from 'rxjs'; +import { skip, first, shareReplay } from 'rxjs/operators'; + +export default ( + observable: Observable, + triggers: C, +) => (InnerComponent: React.ComponentType) => { + class Decorated extends Component { + static displayName: string; + + private subscription?: Subscription; + private sharedObservable: Observable; + + constructor(props: Readonly) { + super(props); + this.sharedObservable = observable.pipe(shareReplay(1)); + + const initializationSubscription = this.sharedObservable + .pipe(first()) + .subscribe(initialState => { + this.state = initialState; + }); + initializationSubscription.unsubscribe(); + } + + componentDidMount() { + this.subscription = this.sharedObservable + .pipe(skip(1)) + .subscribe(newState => { + this.setState(newState); + }); + } + + componentWillUnmount() { + this.subscription!.unsubscribe(); + } + + render() { + return ( + + ); + } + } + + Decorated.displayName = `withObservableStream(${(InnerComponent as any) + .displayName || InnerComponent.name})`; + + return Decorated; +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..439b6aa --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "jsx": "preserve", + "target": "es6", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true + }, + "include": [ + "src" + ] +} From 6dc50543d23f63c8ea1148029b4af35a6bf77772 Mon Sep 17 00:00:00 2001 From: "manuel.soto" Date: Sun, 28 Jul 2019 19:11:00 -0300 Subject: [PATCH 2/2] back to javascript --- package-lock.json | 178 +++++++++++------- package.json | 22 +-- src/{App.tsx => App.js} | 39 +--- src/react-app-env.d.ts | 1 - ...ableStream.tsx => withObservableStream.js} | 27 +-- tsconfig.json | 25 --- 6 files changed, 134 insertions(+), 158 deletions(-) rename src/{App.tsx => App.js} (70%) delete mode 100644 src/react-app-env.d.ts rename src/{withObservableStream.tsx => withObservableStream.js} (50%) delete mode 100644 tsconfig.json diff --git a/package-lock.json b/package-lock.json index 23b705d..769e9bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1902,35 +1902,12 @@ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, "axios": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", - "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", + "version": "0.18.0", + "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", "requires": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "requires": { - "debug": "=3.1.0" - } - }, - "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" - } + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" } }, "axobject-query": { @@ -3542,6 +3519,11 @@ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + }, "core-js-compat": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.0.1.tgz", @@ -4300,6 +4282,14 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "~0.4.13" + } + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -5120,6 +5110,20 @@ "bser": "^2.0.0" } }, + "fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "requires": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, "figgy-pudding": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", @@ -6300,6 +6304,15 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -7708,9 +7721,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash._reinterpolate": { "version": "3.0.0", @@ -8034,9 +8047,9 @@ } }, "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" @@ -8179,6 +8192,15 @@ "lower-case": "^1.1.1" } }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, "node-forge": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", @@ -9749,6 +9771,14 @@ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + }, "promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -9914,14 +9944,14 @@ } }, "react": { - "version": "16.8.6", - "resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz", - "integrity": "sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==", + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz", + "integrity": "sha512-dMv7YrbxO4y2aqnvA7f/ik9ibeLSHQJTI6TrYAenPSaQ6OXfb+Oti+oJiy8WBxgRzlKatYqtCjphTgDSCEiWFg==", "requires": { + "fbjs": "^0.8.16", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.13.6" + "prop-types": "^15.6.0" } }, "react-app-polyfill": { @@ -10043,14 +10073,14 @@ } }, "react-dom": { - "version": "16.8.6", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.6.tgz", - "integrity": "sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==", + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.2.tgz", + "integrity": "sha512-Usl73nQqzvmJN+89r97zmeUpQDKDlh58eX6Hbs/ERdDHzeBzWy+ENk7fsGQ+5KxArV1iOFPT46/VneklK9zoWw==", "requires": { + "fbjs": "^0.8.16", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.13.6" + "prop-types": "^15.6.0" } }, "react-error-overlay": { @@ -10517,9 +10547,9 @@ } }, "rxjs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", - "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.2.tgz", + "integrity": "sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ==", "requires": { "tslib": "^1.9.0" } @@ -10632,15 +10662,6 @@ "xmlchars": "^1.3.1" } }, - "scheduler": { - "version": "0.13.6", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", - "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, "schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -10750,9 +10771,9 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", @@ -11657,6 +11678,11 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "ua-parser-js": { + "version": "0.7.18", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz", + "integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA==" + }, "uglify-js": { "version": "3.4.10", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", @@ -11736,14 +11762,35 @@ } }, "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^2.0.1" + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } } }, "uniq": { @@ -12289,6 +12336,11 @@ } } }, + "whatwg-fetch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" + }, "whatwg-mimetype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", diff --git a/package.json b/package.json index cf3500b..13e7663 100644 --- a/package.json +++ b/package.json @@ -3,28 +3,16 @@ "version": "0.1.0", "private": true, "dependencies": { - "axios": "^0.18.1", - "react": "^16.8.6", - "react-dom": "^16.8.6", - "react-scripts": "3.x", - "rxjs": "^6.5.2" + "axios": "^0.18.0", + "react": "^16.4.2", + "react-dom": "^16.4.2", + "react-scripts": "3.0.1", + "rxjs": "^6.2.2" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] } } diff --git a/src/App.tsx b/src/App.js similarity index 70% rename from src/App.tsx rename to src/App.js index 5a67449..329221e 100644 --- a/src/App.tsx +++ b/src/App.js @@ -1,6 +1,6 @@ import React from 'react'; import axios from 'axios'; -import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; +import { BehaviorSubject, combineLatest } from 'rxjs'; import { map, filter, @@ -13,31 +13,6 @@ import { import withObservableStream from './withObservableStream'; -interface Consumer { - (value: T): void; -} - -interface Story { - objectID: string; - url?: string; - story_url?: string; - title?: string; - story_title?: string; -} - -interface PropsType { - query: string; - subject: string; - stories: Array; -} - -interface TriggersType { - onChangeQuery: Consumer; - onSelectSubject: Consumer; -} - -type AppProps = TriggersType & PropsType; - const SUBJECT = { POPULARITY: 'search', DATE: 'search_by_date', @@ -49,7 +24,7 @@ const App = ({ stories, onChangeQuery, onSelectSubject, -}: AppProps) => ( +}) => (

React with RxJS

@@ -94,7 +69,7 @@ const subject$ = new BehaviorSubject(SUBJECT.POPULARITY); const queryForFetch$ = query$.pipe( debounceTime(1000), distinctUntilChanged(), - filter(Boolean), + filter(Boolean), ); const fetch$ = combineLatest(subject$, queryForFetch$).pipe( @@ -103,12 +78,12 @@ const fetch$ = combineLatest(subject$, queryForFetch$).pipe( ([subject, query]) => axios(`http://hn.algolia.com/api/v1/${subject}?query=${query}`), ), - map(result => result.data.hits as Array), + map(result => result.data.hits), startWith([]), catchError(() => []), ); -const state$: Observable = combineLatest( +const state$ = combineLatest( subject$, query$, fetch$, @@ -120,6 +95,6 @@ const state$: Observable = combineLatest( ); export default withObservableStream(state$, { - onSelectSubject: (subject: string) => subject$.next(subject), - onChangeQuery: (value: string) => query$.next(value), + onSelectSubject: subject => subject$.next(subject), + onChangeQuery: value => query$.next(value), })(App); diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts deleted file mode 100644 index 6431bc5..0000000 --- a/src/react-app-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/src/withObservableStream.tsx b/src/withObservableStream.js similarity index 50% rename from src/withObservableStream.tsx rename to src/withObservableStream.js index febe0f0..db9b276 100644 --- a/src/withObservableStream.tsx +++ b/src/withObservableStream.js @@ -1,18 +1,9 @@ import React, { Component } from 'react'; -import { Observable, Subscription } from 'rxjs'; import { skip, first, shareReplay } from 'rxjs/operators'; -export default ( - observable: Observable, - triggers: C, -) => (InnerComponent: React.ComponentType) => { - class Decorated extends Component { - static displayName: string; - - private subscription?: Subscription; - private sharedObservable: Observable; - - constructor(props: Readonly) { +export default (observable, triggers) => InnerComponent => { + class Decorated extends Component { + constructor(props) { super(props); this.sharedObservable = observable.pipe(shareReplay(1)); @@ -33,22 +24,18 @@ export default ( } componentWillUnmount() { - this.subscription!.unsubscribe(); + this.subscription.unsubscribe(); } render() { return ( - + ); } } - Decorated.displayName = `withObservableStream(${(InnerComponent as any) - .displayName || InnerComponent.name})`; + Decorated.displayName = `withObservableStream(${InnerComponent.displayName || + InnerComponent.name})`; return Decorated; }; diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 439b6aa..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "jsx": "preserve", - "target": "es6", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "allowJs": true, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true - }, - "include": [ - "src" - ] -}