React là gì?
React là một thư viện UI được phát triển tại Facebook để tạo điều kiện cho việc tạo ra các thành phần giao diện người dùng tương tác, trạng thái và có thể tái sử dụng. Nó được sử dụng tại Facebook và Instagram.com được viết hoàn toàn bằng React
Một trong những đặc điểm độc đáo là nó không chỉ được dùng để thực hiện trên phía client, mà nó cũng có thể được render ở phía server và chúng có thể hoạt động tương thích với nhau
Nó cũng sử dụng một khái niệm gọi là DOM ảo để lọc ra các nhánh con của node cần cập nhập dựa trên các thay đổi trạng thái. Nó có thể thực hiện các tương tác với DOM ít nhất để đảm bảo các thành phần luôn được cập nhập
DOM ảo hoạt động như thế nào?
Hãy tưởng tượng bạn có một object mà bạn đã mô hình hoá theo một người. Nó có tất cả các thuộc tính liên quan đến một người có thể có và phản chiếu các trạng thái hiện tại của một người. Về cơ bản đây là những gì React làm với DOM
Hãy tưởng tượng nếu bạn lấy object đó và tạo một vài thay đổi. Thêm ria mép, bắp tay và thay đổi đôi mắt. Trong React, khi chúng ta áp dụng những thay đổi này, hai việc xảy ra. Đầu tiên, React sẽ chạy một thuật toán “diffing” để xác định những gì đã thay đổi. Bước tiếp theo là reconciliation, nơi nó cập nhập DOM với kết quả của diff
Bắt đầu
Để bắt đầu với React, cài đặt công cụ React CLI (Tạo React App) và chạy câu lệnh để tạo một app mới:
# Install the CLI tool npm install -g create-react-app # Create an app create-react-app my-app-name # Install Dependencies cd my-app-name npm install
Cài đặt trang
Khi thiết lập trang của bạn, nếu bạn muốn bao gồm react.js
và react-dom.js
, cũng như script biên dịch Babel. Sau đó bạn viết component của bạn trong script với kiểu đặt là text/babel
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Hello World</title> <script src="https://unpkg.com/react@latest/dist/react.js"></script> <script src="https://unpkg.com/react-dom@latest/dist/react-dom.js"></script> <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> </head> <body> <div id="myDiv"></div> <script type="text/babel"> <!-- React Code Goes Here --> </script> </body> </html>
Trong React, các component được gắn vào một element, nên trong ví dụ này chúng ta sử dụng một div, myDiv
, nó là một vùng chứa chính.
Đây là cách dễ nhất để bắt đầu, thời gian thực sự dùng xây dựng cái gì đấy, nó có thể là ý tưởng tốt để sử dụng Browserify hoặc Webpack ( tạo một app sử dụng Webpack) để thiết lập các component của bạn trong file riêng biệt.
Cơ bản
Các khối xây dựng cơ bản của React được gọi là các components. Ví dụ như sau
<script type="text/jsx"> /** @jsx React.DOM */ React.render( <h1>Hello, world!</h1>, document.getElementById('myDiv') ); </script>
Nếu bạn chưa nhìn những thứ này bao giờ trước đây thì bạn sẽ tự hỏi đoạn code Javscript/HTML được đặt vào đây sẽ hoạt động như thế nào
JSX
Nó được gọi là JSX, và nó là một biến thể cú pháp XML Javascript. Điều này giúp bạn viết các thẻ HTML-ish trong Javascript của bạn. Bạn thực ra chỉ đang viết miêu tả các object dựa trên XML.
Đối với các thẻ HTML thông thường, thuộc tính class
là className
, và thuộc tính for
là htmlFor
trong JSX bởi vì đây là những từ dùng riêng cho Javascript. Bạn có thể xem thêm các khác biệt khác tại đây.
Giờ đây bạn không cần phải dùng JSX, đây là ví dụ cú pháp được trông ra sao mà không cần nó
/** @jsx React.DOM */ React.render( React.DOM.h1(null, 'Hello, world!'), document.getElementById('myDiv') );
Bạn có thể đọc thêm các element được hỗ trợ ở đây nếu bạn thích
Trong đoạn code đầu tiên, bạn có để ý /** @jsx React.DOM */
ở trên đầu không? Cái này là quan trọng, nó nói với React rằng chúng ta đang sử dụng JSX và đánh dấu cần được chuyển đổi, nên bạn cần bao gồm nó khi sử dụng cú pháp JSX.
Components
Khi sử dụng phương thức render
ở trên, tham số đầu tiên là các thành phần chúng ta muốn render
, tham số thứ hai là Node DOM mà ta muốn gắn vào. Chúng ta có thể dụng phương thức createClass
để tạo các class Component tuỳ chỉnh. Nó lấy một object xác định như một tham số, chúng ta sẽ tạo nó như bên dưới.
var MyComponent = React.createClass({ render: function(){ return ( <h1>Hello, world!</h1> ); } });
Sau đó chúng ta có thể tạo một class, chúng ta có thể render nó trong document của chúng ta như sau
React.render( <MyComponent/>, document.getElementById('myDiv') );
Props
Khi chúng ta sử dụng các Component được định nghĩa, chúng ta có thể thêm các thuộc tính được gọi là props. Những thuộc tính này có thể dùng trong Component như this.props
và có thể được dùng trong phương thức render để biểu diễn dữ liệu thay đổi
var MyComponent = React.createClass({ render: function(){ return ( <h1>Hello, {this.props.name}!</h1> ); } }); React.render(<MyComponent name="Handsome" />, document.getElementById('myDiv'));
Specs, lifecycle và state
Phương thức render
là thông số cần thiết duy nhất cho việc tạo component, nhưng có một vài phương thức liffecycle và specs chúng ta có thể sử dụng rất hữu ích khi bạn thực sự muốn component của bạn làm bất cứ điều gì.
Các phương thức lifecycle
Đây là một vài phương thức lifecyle trong React bạn nên biết
- componentWillMount: Được gọi một lần, trên cả client và server trước khi quá trình render diễn ra
- componentDidMount: Được gọi một lần, chỉ trên client sau khi quá trình render diễn ra
- shouldComponentUpdate: Được gọi trước khi quá trinh unmount(huỷ) component
Specs
- getInitialState: Giá trị trả về là giá trị ban đầu cho state
- getDefaultProps: Đặt các giá trị props dự phòng nếu props không được cung cấp.
- mixins: Một mảng các object, thường được sử dụng để mở rộng chức năng của các Component hiện tại
Có nhiều phương thức lifecycle và specs khác nữa, bạn có thể đọc thêm ở đây
State
Tất cả các component đều có một object state
và một object props
. State được gán bằng cách sử dụng phương thức setState
. Gọi setState
gây ra việc cập nhập UI và là không thể thiếu của tương tác React. Nếu bạn muốn gán cho một state ban đầu trước khi bất kỳ sự tương tác nào xảy ra chúng ta có thể sử dụng phương thức getInitialState
. Bên dưới đây, chúng ta biết làm thế nào để gán cho state của component.
var MyComponent = React.createClass({ getInitialState: function(){ return { count: 5 } }, render: function(){ return ( <h1>{this.state.count}</h1> ) } });
Các Event
React cũng có hệ thống event tích hợp. Các event được đính kèm như các thuộc tính của các component và có thể kích hoạt các phương thức. Chúng ta sẽ cho phép tăng dần số đếm mỗi khi có event click xảy ra như bên dưới đây.
/** @jsx React.DOM */ var Counter = React.createClass({ incrementCount: function(){ this.setState({ count: this.state.count + 1 }); }, getInitialState: function(){ return { count: 0 } }, render: function(){ return ( <div class="my-component"> <h1>Count: {this.state.count}</h1> <button type="button" onClick={this.incrementCount}>Increment</button> </div> ); } }); React.render(<Counter/>, document.getElementById('myDiv'));
Luồng dữ liệu một chiều
Trong React, luồng dữ liệu ứng dụng một chiều thông qua các object state
và props
, trái ngược với ràng buộc 2 chiều của thư viện Angular. Điều này nghĩa là trong một Component đa thành phần, thông thường một component cha nên quản lý state và truyền nó xuống Component con thông qua props
State của bạn nên được cập nhập sử dụng phương thức setState
để đảm bảo rằng việc làm mới UI sẽ xảy ra, nếu cần thiết. Các giá trị kết quả nên được truyền xuống các component con sử dụng các thuộc tính mà có thể truy cập được ở thành phần con thông qua this.props
Xem ví dụ này để thấy khái niệm trên trong thực tế
/** @jsx React.DOM */ var FilteredList = React.createClass({ filterList: function(event){ var updatedList = this.state.initialItems; updatedList = updatedList.filter(function(item){ return item.toLowerCase().search( event.target.value.toLowerCase()) !== -1; }); this.setState({items: updatedList}); }, getInitialState: function(){ return { initialItems: [ "Apples", "Broccoli", "Chicken", "Duck", "Eggs", "Fish", "Granola", "Hash Browns" ], items: [] } }, componentWillMount: function(){ this.setState({items: this.state.initialItems}) }, render: function(){ return ( <div className="filter-list"> <input type="text" placeholder="Search" onChange={this.filterList}/> <List items={this.state.items}/> </div> ); } }); var List = React.createClass({ render: function(){ return ( <ul> { this.props.items.map(function(item) { return <li key={item}>{item}</li> }) } </ul> ) } }); React.render(<FilteredList/>, document.getElementById('myDiv'));