{"id":22707313,"url":"https://github.com/tutv/rn-hacker-news","last_synced_at":"2026-05-05T19:31:34.915Z","repository":{"id":85524347,"uuid":"142603579","full_name":"tutv/rn-hacker-news","owner":"tutv","description":"Build Hacker News app with React Native","archived":false,"fork":false,"pushed_at":"2018-08-02T04:20:28.000Z","size":1153,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-11T13:33:58.423Z","etag":null,"topics":["fetch","fetch-api","hacker-news","react-native","reactjs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tutv.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-27T17:04:58.000Z","updated_at":"2020-09-13T09:44:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"8b19341a-0bfe-447c-89d8-b00449d78e90","html_url":"https://github.com/tutv/rn-hacker-news","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tutv/rn-hacker-news","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tutv%2Frn-hacker-news","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tutv%2Frn-hacker-news/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tutv%2Frn-hacker-news/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tutv%2Frn-hacker-news/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tutv","download_url":"https://codeload.github.com/tutv/rn-hacker-news/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tutv%2Frn-hacker-news/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32664777,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-05T11:29:49.557Z","status":"ssl_error","status_checked_at":"2026-05-05T11:29:48.587Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fetch","fetch-api","hacker-news","react-native","reactjs"],"created_at":"2024-12-10T10:12:01.400Z","updated_at":"2026-05-05T19:31:34.893Z","avatar_url":"https://github.com/tutv.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sử dụng Fetch API xây dựng ứng dụng Hacker News\n\n## Mục tiêu\n\n- Biết cách sử dụng `Fetch API` để tạo HTTP request.\n- Biết thay đổi các tham số trong `Fetch API` để tạo các request khác nhau.\n- Biết cách gọi request trong `life cycle` của React một cách đúng đắn.\n\n## Mô tả\n\n- Tạo 1 ứng dụng với chức năng hiển thị danh sách tin tức từ [Hacker News](https://github.com/HackerNews/API)\n\n## Hướng dẫn\n\n### Bước 1\n\n- Tạo project với `create-react-native-app`.\n\n### Bước 2\n\n- Tạo 1 component `HomePage` trong đó có chứa 2 component `Header` và `TopNews`.\n\n### Bước 3\n\n- Trong `TopNews` component chúng ta sẽ gọi đến API tại hook `componentDidMount`:\n\n```javascript\nimport React, {Component} from 'react'\nimport {View, Text, ScrollView, RefreshControl, StyleSheet} from 'react-native'\nimport NewsItem from \"./NewsItem\"\n\nclass TopNews extends Component {\n    state = {\n        news: [],\n        error: '',\n        loading: false\n    }\n\n    _mounted = false\n\n    componentDidMount() {\n        this._mounted = true\n        this._fetchListNews()\n    }\n\n    componentWillUnmount() {\n        this._mounted = false\n    }\n\n    _fetchListNews = () =\u003e {\n        if (this.state.loading) return\n\n        this.setState({loading: true})\n\n        fetch('https://hacker-news.firebaseio.com/v0/topstories.json')\n            .then(response =\u003e response.json())\n            .then(result =\u003e {\n                if (!this._mounted) return\n\n                this.setState({\n                    loading: false,\n                    news: Array.isArray(result) ? result : [],\n                    error: ''\n                })\n            })\n            .catch(error =\u003e {\n                if (!this._mounted) return\n                const message = error.message || 'Fetch list news failed'\n\n                this.setState({\n                    error: message,\n                    loading: false\n                })\n            })\n    }\n\n    _handleRefresh = () =\u003e {\n        this._fetchListNews()\n    }\n\n    render() {\n        const {news, error, loading} = this.state\n\n        return (\n            \u003cView style={styles.container}\u003e\n                \u003cScrollView refreshControl={\n                    \u003cRefreshControl\n                        refreshing={loading}\n                        onRefresh={this._handleRefresh}/\u003e\n                }\u003e\n                    {\n                        !!error ? \u003cText\u003e{error}\u003c/Text\u003e\n                            : news.map((id, index) =\u003e {\n                                return \u003cNewsItem key={id} index={index} id={id}/\u003e\n                            })\n                    }\n                \u003c/ScrollView\u003e\n            \u003c/View\u003e\n        )\n    }\n}\n\nconst styles = StyleSheet.create({\n    container: {\n        flex: 1,\n        width: '100%',\n        backgroundColor: '#f6f6ef',\n        paddingLeft: 10,\n        paddingTop: 10,\n        paddingBottom: 10\n    }\n})\n\nexport default TopNews\n```\n\nNote: Ở trong component này có sử dụng `RefreshControl` để cho phép người dùng refesh lại danh sách news.\n\n### Bước 4\n\n- Do API lấy danh sách news chỉ lấy ra được `ID` của news nên trong từng `NewsItem` chúng ta sẽ gọi tiếp API để lấy ra nội dung của news đó.\n\n- Trong component `NewsItem` chúng ta sẽ gọi API tại hook `componentDidMount` và gọi lại API khi `ID` của nó thay đổi bằng cách kiểm tra trong hook `componentDidUpdate`.\n\n```javascript\nimport React, {Component} from 'react'\nimport PropTypes from 'prop-types'\nimport {View, Text, StyleSheet} from 'react-native'\nimport moment from 'moment'\n\nclass NewsItem extends Component {\n    state = {\n        news: {},\n        loading: false\n    }\n\n    componentDidMount() {\n        const {index} = this.state\n        setTimeout(() =\u003e {\n            this._fetchDetail()\n        }, index * 1000 || 0)\n    }\n\n    componentDidUpdate(prevProps, prevState) {\n        if (prevProps.id !== this.props.id) {\n            this._fetchDetail()\n        }\n    }\n\n    _fetchDetail = () =\u003e {\n        const {id} = this.props\n\n        this.setState({\n            loading: true\n        })\n\n        fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json`)\n            .then(response =\u003e response.json())\n            .then(result =\u003e {\n                this.setState({\n                    news: result ? result : {},\n                    loading: false\n                })\n            })\n            .catch(error =\u003e {\n                console.error('Fetch error', error)\n\n                this.setState({loading: false})\n            })\n    }\n\n    render() {\n        const {index} = this.props\n        const {news, loading} = this.state\n\n        const score = news.score || 0;\n        const pointText = score \u003e 1 ? 'points' : 'point'\n        const timeAgo = moment(news.time * 1000).fromNow()\n\n        return (\n            \u003cView style={styles.container}\u003e\n                \u003cView style={styles.left}\u003e\n                    \u003cText style={styles.index}\u003e{index + 1}.\u003c/Text\u003e\n                \u003c/View\u003e\n                \u003cView style={styles.right}\u003e\n                    \u003cText style={styles.title}\u003e\n                        {\n                            loading ? 'Loading...' : news.title\n                        }\n                    \u003c/Text\u003e\n                    {\n                        !!news \u0026\u0026 Object.keys(news).length \u0026\u0026\n                        \u003cText style={styles.meta}\u003e{news.score || 0} {pointText} {timeAgo}\u003c/Text\u003e\n                    }\n                \u003c/View\u003e\n            \u003c/View\u003e\n        )\n    }\n}\n\nNewsItem.propTypes = {\n    id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,\n    index: PropTypes.number.isRequired,\n}\n\nconst styles = StyleSheet.create({\n    container: {\n        flex: 1,\n        flexDirection: 'row',\n        marginBottom: 10,\n    },\n\n    left: {\n        marginRight: 10\n    },\n\n    right: {},\n\n    index: {\n        color: '#828282',\n        fontSize: 14,\n        minWidth: 15,\n        textAlign: 'right'\n    },\n\n    title: {\n        color: '#000',\n        fontSize: 14,\n        marginRight: 20,\n        flex: 1,\n        flexWrap: 'wrap'\n    },\n\n    meta: {\n        color: '#828282',\n        fontSize: 12\n    }\n})\n\nexport default NewsItem\n```\n\n### Bước 5\n\n- Chạy chương trình và quan sát kết quả.\n\n## Mã nguồn\n\nTham khảo tại: https://github.com/tutv/rn-hacker-news\n\n## Ảnh demo\n![Home page](/demo/home.jpeg)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftutv%2Frn-hacker-news","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftutv%2Frn-hacker-news","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftutv%2Frn-hacker-news/lists"}