1. Sử dụng Hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>ReactJS</title> </head> <body> <div id="app"></div> <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <script type="text/babel"> const { useState, useEffect } = React; function Content() { const [user, setUser] = useState([]); const [userID, setUserID] = useState(1); const [loading, setLoading] = useState(false); const apiFakeData = async (id) => { try { let url = `https://reqres.in/api/users/${id}`; let response = await fetch(url); if (response.ok) { let responseJSON = await response.json(); setUser(responseJSON.data); } else if (response.status === 404) { console.log("Lỗi 404"); setUser({error: 404}); } else { console.log("Lỗi khác"); setUser({error: response.status}); } } catch (error) { console.log("Lỗi kết nối: ", error); setUser({error: error.toString()}) } finally { setLoading(false) } } // Nếu không dùng cleanup, component bị unmout trong quá trình đang getAPI // Lúc đó, update State khi component unmout sẽ gây ra lỗi // Đếch hiểu tại sao, cứ dùng hàm cleanup trong useEffect thì khi remove Component đi thì nó cũng tự hết lỗi :3 useEffect(() => { setLoading(true) // Cái API này nhanh quá, cho delay 500ms cho chậm lại setTimeout(() => { apiFakeData(userID); }, 500); }, [userID]); console.log("Content: Render", loading, userID); return ( <div> <input type="number" value={userID} onChange={e => setUserID(e.target.value)} /> {loading ? <p>Loading...</p> : <p>{JSON.stringify(user, null, 2)}</p>} </div> ); } function App() { const [showContent, setShowContent] = useState(true) return ( <div> <button onClick={() => { setShowContent(!showContent) }}>Toggle Content Component</button> {showContent && <Content />} </div> ); } ReactDOM.render(<App />, document.getElementById('app')); </script> </body> </html> |
2. Sử dụng Class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>ReactJS</title> </head> <body> <div id="app"></div> <script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.js"></script> <script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <script type="text/babel"> class Content extends React.Component { constructor(props) { super(props); this.isComponentMounted = false; this.state = { loading: false, user: [], userID: 1, }; } //Hành động thay đổi state bằng api phải để trong componentDidMount và componentDidUpdate componentDidMount() { this.isComponentMounted = true; this.getData(this.state.userID); } //Chỉ khi thay đổi giá trị userID mới render lại componentDidUpdate(prevProps, prevState) { if (prevState.userID == this.state.userID) return; this.getData(this.state.userID); } //Dùng isComponentMounted, mục đích là khi Component đã unmount, thì không thể setState được nữa //Thử tắt dòng isComponentMounted = false và test Togggle Component biết liền à componentWillUnmount() { this.isComponentMounted = false; } getData = (id) => { //Bắt đầu load thì để loading: true this.setState({ loading: true }); //Tốc độ cái API này nhanh quá, nên phải để nó Delay 500s :3 setTimeout(() => { this.apiFakeData(id); }, 500); } apiFakeData = async (id) => { try { let url = `https://reqres.in/api/users/${id}`; let response = await fetch(url); if (this.isComponentMounted) { if (response.ok) { let responseJSON = await response.json(); this.setState({ user: responseJSON.data }); } else if (response.status === 404) { console.log("Lỗi 404"); this.setState({ user: { error: 404 } }); } else { console.log("Lỗi khác"); this.setState({ user: { error: response.status } }); } } } catch (error) { if (this.isComponentMounted) { console.log("Lỗi kết nối"); this.setState({ user: { error: error.toString() } }); } } finally { this.setState({ loading: false }); } } render() { console.log("Content: Render"); return ( <div> <input type="number" value={this.state.userID} onChange={e => this.setState({ userID: e.target.value })} /> {this.state.loading ? <p>Loading...</p> : <p>{JSON.stringify(this.state.user, null, 2)}</p>} </div> ); } } class App extends React.Component { constructor(props) { super(props); this.state = { showContent: true, }; } // Dùng button Toggle Component để test chức năng isComponentMounted ở Content // Trường hợp unmout nhanh quá, mà getAPI về chậm, sau đó lại setState ở Component đã unmount ==> sẽ gây ra lỗi // Mục đích dùng "isComponentMounted" để tránh việc setState cho những Component đã unmount render() { return ( <div> <button onClick={() => { this.setState({ showContent: !this.state.showContent }) }}>Toggle Content Component</button> {this.state.showContent && <Content />} </div> ); } } ReactDOM.render(<App />, document.getElementById('app')); </script> </body> </html> |