Tạo mới ứng dụng
- Cách tạo ứng dụng ReactJs phổ biến là sử dụng công cụ create-react-app như hướng dẫn trên trang chủ của ReactJs. Tuy nhiên, để dễ nắm bắt các khái niệm và cách hoạt động của ReactJs, có thể tạo ứng dụng bằng tạo một file html duy nhất.
ReactJS sử dụng JSX để biểu diễn các element. Thực chất của JSX là các lệnh javascript nhưng được viết dưới dạng gần giống với html để thể hiện cấu trúc của các component. Do JSX không phải là ngôn ngữ mặc định được trình duyệt hỗ trợ, để chạy được JSX trong file html, cần sử dụng Babel để dịch JSX sang Javascript.
- Ứng dụng ReactJS đơn giản đầu tiên:
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <div id="app"></div>
<script type="text/babel"> function App() { return <div>Hello</div>; } ReactDOM.render(<App />, document.getElementById('app')); </script> |
Lưu chương trình trên dưới dạng một file html, sau đó mở bằng trình duyệt, chương trình sẽ hiện dòng thông báo “Hello” trên cửa sổ trình duyệt.
- Cách thức hoạt động của ứng dụng ReactJs
- Nội dung ứng dụng được chứa trong một element gốc (root / container). Ở ví dụ trên, thẻ div với id bằng “app” là root của ứng dụng.
- Ứng dụng được hiển thị nhờ hàm ReactDom.render :
ReactDOM.render(<App />, document.getElementById('app'))
Hàm này thực hiện hiển thị nội dung của component được chỉ định (<App/>) vào trong khu vực của element gốc của ứng dụng (<div id='app'>)
- Các phần tử cấu thành nên ứng dụng ReactJs là các component, chúng tương tự các element của html : được kí hiệu bằng các thẻ, có các thuộc tính, sự kiện … Để khai báo một component, có thể sử dụng các cách sau:
- Khai báo component dưới dạng function, như cách ví dụ trên khai báo component App. Hàm khai báo component cần trả về nội dung hiển thị dạng JSX của component
- Khai báo component dưới dạng class. Trong class này, cần có hàm render() trả về nội dung hiện thị dưới dạng JSX của component:
class App extends React.Component { render() { return <div>Hello</div>; } } |
Có thể hiểu cách khai báo component theo function là trường hợp riêng của cách khai báo theo class, khi class chỉ có một hàm render() duy nhất.
Gắn dữ liệu trong các component
- Nội dung hiển thị của các component được thể hiện dưới dạng JSX. Trong nội dung dạng JSX này, có các phần tử static text tương ứng với nội dung html thông thường, ngoài ra còn có các đoạn template cho phép gắn dữ liệu từ các biến Javascript vào html.
Ví dụ:
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <div id="app"></div>
<script type="text/babel"> class App extends React.Component { constructor() { super(); this.message = "Hello"; } render() { return <div>{ this.message }</div>; } } ReactDOM.render(<App />, document.getElementById('app')); </script> |
Ở ví dụ trên, nội dung JSX của component App là:
<div>{ this.message }</div>
Cú pháp { <biểu_thức_js> } là một cách viết để thực hiện gắn dữ liệu từ các biến javascript vào html. Khi ứng dụng ReactJs chạy, các đoạn { <biểu_thức_js> } sẽ được thay bằng giá trị của biểu thức bên trong dấu cặp ngoặc nhọn {}, và nội dung html sau khi biên dịch mới được hiển thị lên trình duyệt. Ở ví dụ trên, nội dung html của component App sẽ được biên dịch thành:
<div>Hello</div>
- Cách gắn dữ liệu trong ReactJs là cách gắn dữ liệu một chiều (one-way-binding). Có thể dùng hàm setState của class React.Component để cập nhật nội dung của component theo các biến trạng thái, tuy nhiên người dùng thay đổi dữ liệu của các component thì giá trị của các biến trạng thái không thay đổi.
Thuộc tính của các component
- Mỗi component của React có thể được truyền vào các thuộc tính tương tự như các thuộc tính của các thẻ html.
Ví dụ:
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <div id="app"></div>
<script type="text/babel"> function Block(props) { return <div>{props.text}</div> } function App() { return (<div> <Block text="Block 1"></Block> <Block text={"Block 2"}></Block> </div>); } ReactDOM.render(<App />, document.getElementById('app')); </script> |
Ở ví dụ trên, các component Block bên trong component App được truyền vào thuộc tính text theo cách:
<Block text="Block 1"></Block> <Block text={"Block 2"}></Block> |
Ở cách thứ nhất, thuộc tính text là một string, do đó được viết tương tự như cách viết thuộc tính của các thẻ html. Ở cách thứ 2, thuộc tính text được truyền vào dưới dạng một biểu thức javascript, do đó nội dung được đặt trong cặp dấu ngoặc nhọn {}
Trong hàm hiển thị của component Block, các thuộc tính được lấy ra từ biến props đóng vai trò như tham số của hàm hiển thị:
function Block(props) { return <div>{props.text}</div> } |
Nếu sử dụng cách khai báo component theo class thì thuộc tính của component được lấy ra từ trường props kế thừa từ class React.Component:
class Block extends React.Component { render() { return <div>{this.props.text}</div> } } |
Xử lý các sự kiện cho các component
- Các hàm xử lý sự kiện cho các component cũng được truyền vào tương tự các thuộc tính, chỉ khác là giá trị của biểu thức là một hàm của Javascript.
Ví dụ:
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <div id="app"></div>
<script type="text/babel"> function App() { return ( <div> <button onClick={() => alert("Test")}>Test</button> </div> ) } ReactDOM.render(<App />, document.getElementById('app')); </script> |
- Dùng hàm xử lý sự kiện để lấy giá trị của các thẻ input:
Do ReactJs sử dụng gắn dữ liệu một chiều (one-way-binding, như đã nói ở phần trước), nên để lấy dữ liệu của các thẻ input do người dùng nhập vào, thường sử dụng sử kiện onChange của các thẻ input để cập nhật giá trị của các biến trạng thái:
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <div id="app"></div>
<script type="text/babel"> class App extends React.Component { constructor(props) { super(props); this.state = { }; } mySubmitHandler = (e) => { e.preventDefault(); alert("Tên:" + this.state.name + ", địa chỉ:" + this.state.address); } myChangeHandler = (e) => { this.setState({ [e.target.name]: e.target.value }); } render() { return ( <form onSubmit={this.mySubmitHandler}> <p>Họ tên : <input name='name' onChange={this.myChangeHandler} /> </p> <p>Địa chỉ: <input name='address' onChange={this.myChangeHandler} /> </p> <input type="submit"/> </form> ); } }
ReactDOM.render(<App />, document.getElementById('app')); </script> |
Hiển thị có điều kiện
- Trong một số trường hợp, chương trình có thể hiển thị hoặc không hiển thị một/một số thẻ html tùy theo trạng thái của ứng dụng. Để thực hiện việc này, có thể sử dụng phép tính && của javascript :
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <div id="app"></div>
<script type="text/babel"> class App extends React.Component { constructor() { super(); this.state = { message: "Hello", show: true } }
render() { return ( <div> {this.state.show && <div>{ this.state.message }</div> } <button onClick={() => this.setState({show:true}) }>Show</button> <button onClick={() => this.setState({show:false}) }>Hide</button> </div>) } } ReactDOM.render(<App />, document.getElementById('app')); </script> |
Hiển thị từ một danh sách
- Khi muốn hiển thị một danh sách các thẻ html từ một mảng dữ liệu (với các thẻ ul, table , …), có thể sử dụng hàm map của array trong javascript:
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <div id="app"></div>
<script type="text/babel"> class App extends React.Component { constructor() { super(); this.state = { students: ["Nguyen Van A", "Nguyen Van B"] } }
render() { return ( <ul> { this.state.students.map(st => ( <li>{st}</li> ) ) } </ul> ) } } ReactDOM.render(<App />, document.getElementById('app')); </script> |
Ngoài ra mỗi element trong vòng lặp nên có thêm thuộc tính key để giúp ReactJs dễ update việc hiển thị danh sách khi dữ liệu thay đổi. Giá trị của key cần duy nhất giữa các element với nhau, do đó thông thường sẽ sử dụng thuộc tính id của mỗi bản ghi trong tập dữ liệu. Nếu các bản ghi không có id, có thể dùng biến chỉ số vòng lặp để làm key, ví dụ:
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <div id="app"></div>
<script type="text/babel"> class App extends React.Component { constructor() { super(); this.state = { students: ["Nguyen Van A", "Nguyen Van B"] } }
render() { return ( <ul> { this.state.students.map((st,i) => ( <li key={i}>{st}</li> ) ) } </ul> ) } } ReactDOM.render(<App />, document.getElementById('app')); </script> |
Vòng đời của component
- Mỗi component của ReactJs khi được hiển thị sẽ lần lượt gọi các hàm sau:
- constructor() : Hàm khởi tạo của class
- getDerivedStateFromProps() : Hàm được gọi trước khi component được hiển thị (render). Hàm này thường dùng để tính một số biến trạng thái (state) của component dựa trên các thuộc tính (props) truyền vào component.
- render() : Hàm hiển thị component thành DOM
- componentDidMount() : Thường dùng để gọi các chức năng khởi tạo mà yêu cầu component đã xuất hiện trong DOM
Ví dụ:
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <div id="app"></div>
<script type="text/babel"> class App extends React.Component { constructor() { super(); this.state = {} } componentDidMount() { this.setState({message: "Hello"}); }
render() { return ( <div>{this.state.message}</div> ) } } ReactDOM.render(<App />, document.getElementById('app')); </script> |
Lấy dữ liệu từ server
- Để lấy dữ liệu từ server, có thể dùng các thư viện như axios, hoặc dùng hàm fetch của javascript. Do hàm fetch là hàm async, do đó các hàm lấy dữ liệu cũng phải khai báo async, và khi gọi hàm phải có thêm await ở trước.
Ví dụ:
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <div id="app"></div>
<script type="text/babel"> class App extends React.Component { constructor() { super(); this.state = { server_url: "http://api.openweathermap.org/data/2.5/weather", location_id: "1581129", api_key: "d6477696b63c2e661af64eead58c11d9", } }
getData = async () => { var url = this.state.server_url + `?id=${this.state.location_id}&units=metric&appid=${this.state.api_key}`; var response = await fetch(url); var current_weather = await response.json(); this.setState({current_weather}) }
render() { return ( <div> {this.state.current_weather && <div> <p><b>Thời tiết Hà Nội hiện tại</b></p> <p>Nhiệt độ : {this.state.current_weather.main.temp} °C</p> <p>Độ ẩm : {this.state.current_weather.main.humidity} %</p> <p>Áp suất khí quyển : {this.state.current_weather.main.pressure / 1000} atm</p> </div> }
<br /> <button onClick={this.getData}>Lấy thông tin thời tiết</button> </div>) } } ReactDOM.render(<App />, document.getElementById('app')); </script> |