+1

Ứng dụng realtime sử dụng ReactJs với Php

Hôm nay mình sẽ đi cùng các bạn đến với việc sử dụng ReactJs và với phía backend là Php. Thực ra trong bài này chủ yếu chúng ta tìm hiểu cách thức hoạt động của ReactJs là chủ yếu, bình thường mọi người sẽ thường nghĩa đến ReactJs làm với NodeJs và SocketIo, nay mình muốn thử ReactJs làm với server là Php thì sẽ ra sao.

Bài toán đưa ra

Vấn đề ở đây mình đưa ra khá đơn giản, đó là việc làm đơn hàng. Trong đó có list danh sách đơn hàng sau đó ở dưới nhập đơn hàng (mã sản phẩm + số lượng) sau đó cập nhập luôn trên danh sách và lưu DB. Đầu tiên ta cần tạo database. Thì ở đây cho đơn giản tôi chỉ tạo 2 bảng là bảng products và bảng orders như sau

CREATE TABLE products (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(30),
price INT(6)
)

CREATE TABLE orders (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
product_id INT(6),
quantity INT(6)
)

Xử lý database từ phía server

Ở đây ta thấy có 2 công việc về phía server cần làm đó là gọi danh sách order và thêm 1 order mới. Vì sẽ gọi ajax nên ta sẽ tạo 2 file là get_orders.php với add_order.php như sau:

<?php

require_once __DIR__ . '/core/database.php';

$database = new Database();
$response = json_encode($database->getOrders());
header('Content-type: application/json');
echo $response;

<?php

require_once __DIR__ . '/core/database.php';
if (isset($_REQUEST['product_id'])) {
    $productId = $_REQUEST['product_id'];
    $quantity = $_REQUEST['quantity'] ?? 1;
    $database = new Database();
    $response = json_encode($database->addOrder($productId, $quantity));
    $response = json_encode($database->getOrders());
    header('Content-type: application/json');
    echo $response;
}

Cả 2 file trên bạn đều thấy khi trả về ta phải trả về kiểu json khi đó reactJs mới hiểu dữ liệu trả về là như thế nào. Để hiểu thêm việc lấy csdl như thế nào, mình lấy 1 cách đơn giản như sau. Dưới đây chỉ là source kết nối csdl rất đơn giản:

<?php
class Database {
    private $servername = 'localhost';
    private $username = 'root';
    private $password = 'root';
    private $dbname = 'training';
    public function __construct()
    {

    }

    private function connect()
    {
        $conn = new mysqli($this->servername, $this->username, $this->password, $this->dbname);

        return $conn;
    }

    public function getProducts()
    {
        $sql = $this->connect();
        $data = $sql->query('Select * from products');
        $sql->close();
        $products = [];
        while ($row = $data->fetch_object()){
            $products[] = $row;
        }

        return $products;
    }

    public function addOrder($productId, $quantity)
    {
        $sql = $this->connect();
        $sql->query('insert into orders(product_id, quantity) VALUES('. $productId . ', ' . $quantity .')');
        $sql->close();

        return true;
    }

    public function getOrders()
    {
        $sql = $this->connect();
        $data = $sql->query('Select orders.quantity, products.name, products.price from orders left join products on products.id = orders.product_id order by orders.id desc');
        $sql->close();
        $orders = [];
        while ($row = $data->fetch_object()){
            $orders[] = $row;
        }

        return $orders;
    }
}

Phần view

Đầu tiên ta tạo 1 file html, file này đơn thuần chỉ là load thư viên js (jquery, reactJs,...)

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Study React with Php - Framgia</title>
    <!-- Not present in the tutorial. Just for basic styling. -->
    <link rel="stylesheet" href="style/style.css" />
    <script src="https://unpkg.com/react@15.3.0/dist/react.js"></script>
    <script src="https://unpkg.com/react-dom@15.3.0/dist/react-dom.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
    <script src="https://unpkg.com/jquery@3.1.0/dist/jquery.min.js"></script>
    <script src="https://unpkg.com/remarkable@1.7.1/dist/remarkable.min.js"></script>
  </head>
  <body>
    <div id="content"></div>
    <script type="text/babel" src="js/function.js"></script>
    <script type="text/babel">
      // To get started with this tutorial running your own code, simply remove
      // the script tag loading scripts/example.js and start writing code here.
    </script>
  </body>
</html>

Xử lý phía client bằng ReactJs

Ở đây ta nên hiểu bố cục của React sẽ như sau: ---Product Box ------List Products --------Product ------Add order form Qua bố cục ở đây thi ta hiểu cần phải làm từng khối một, từ trong ra ngoài, đầu tiên làm tử Product

Product


var Product = React.createClass({
  render: function () {
    return (
      <div className="item">
        <div className="name">{this.props.item.name}</div>
        <div className="price">{this.props.item.price}</div>
        <div className="quantity">{this.props.item.quantity}</div>
        <div className="subTotal">{this.props.item.subTotal}</div>
      </div>
    );
  }
});

Ở đây ta hiểu Product sẽ trả về là 1 div với các thông tin như name, price quantitysubTotal. Như vậy khi gọi đến class này ta cần truyền biến cho nó là 1 biên tên là item với các thuộc tính là** name, price, quantity** và subTotal. Việc truyền vào ta sẽ truyền từ Product List dưới đây.

Product List

var ProductList = React.createClass({
  render: function() {
    var total = 0;
    var products = this.props.data.map(function (product) {
      total += product.price * product.quantity;
      product.subTotal = product.price * product.quantity;
      return (
        <Product item={product} key={product.id} />
      );
    });
    return (
      <div className="product-list">
        <div className="header">
          <div className="name">Name</div>
          <div className="price">Price</div>
          <div className="quantity">Quantity</div>
          <div className="subTotal">Sub Total</div>
        </div>
        {products}
        <div className="footer">
          Total: {total}
        </div>
      </div>
    );
  }
});

Ở đây ta có thể thấy việc truyền param là data gồm danh sách các order gồm thông tin như name, price, quantity từ đó tự tính subTotal cũng như tổng giá tiền.

Order Form

Tiếp theo ta tạo tiếp 1 class nữa là Order Form, tức là ở đây ta sẽ tạo 1 form gồm 2 input nhập số product id và số quantity.

var OrderForm = React.createClass({
  getInitialState: function() {
    return {product_id: '', quantity: ''};
  },
  handleProductIdChange: function(e) {
    this.setState({product_id: e.target.value});
  },
  handleQuantityChange: function(e) {
    this.setState({quantity: e.target.value});
  },
  handleSubmit: function(e) {
    e.preventDefault();
    var productId = this.state.product_id.trim();
    var quantity = this.state.quantity.trim();
    this.props.onOrderSubmit({product_id: productId, quantity: quantity});
    this.setState({product_id: '', quantity: ''});
  },
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input
          type="text"
          placeholder="Product Id"
          value={this.state.product_id}
          onChange={this.handleProductIdChange}
        />
        <input
          type="text"
          placeholder="Quantity"
          value={this.state.quantity}
          onChange={this.handleQuantityChange}
        />
        <input type="submit" value="Send" />
      </form>
    );
  }
});

Tại đây ta cần lưu ý đó là ta tạo 2 input và khi thay đổi 2 input đó thì gọi đến function handleProductIdChange() và handleQuantityChange(). Việc này mục đích gán giá trị cho 2 biến là product_id và quantity để gửi lên server. Và sự kiện submit sẽ gọi đến handleSubmit() và hàm này được xử lý ở trong class Product Box dưới đây

Product Box

var ProductBox = React.createClass({
  //Goi ajax load product vao data
  loadData: function () {
    $.ajax({
      url: 'get_orders.php',
      dataType: 'json',
      cache: false,
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  submitOrder: function (order) {
    $.ajax({
      url: 'add_order.php',
      type: 'POST',
      dataType: 'json',
      data: order,
      cache: false,
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  getInitialState: function() {
    return {data: []};
  },
  //Setup chay ajax theo 1 khoang thoi gian
  componentDidMount: function() {
    this.loadData();
    setInterval(this.loadData, 2000);
  },
  render: function () {
    return  (
      <div className="product-box">
        <ProductList data={this.state.data} />
        <OrderForm onOrderSubmit={this.submitOrder}/>
      </div>
    )
  }
});

Đây có thể hiểu như 1 class quản lý tất cả những class trên. Trong này có function loadData() là để gọi dữ liệu từ server lên. Rồi function addOrder() nữa. Để tạo thuộc tính realtime thì ta cứ cho 2s thì gọi lên servere 1 lần bằng hàm:

  componentDidMount: function() {
    this.loadData();
    setInterval(this.loadData, 2000);
  }

Lưu ý để chạy được hàm này ta cần phải setup trạng thaí ban đầu đã:

  getInitialState: function() {
    return {data: []};
  },

Kết nối đến view bên ngoài

Sau khi có các class trên việc cuối cùng ta chỉ định ProductBox sẽ được gán vào đâu bằng đoạn lệnh ngắn gọn sau:

ReactDOM.render(
<ProductBox />,
document.getElementById('content')
);

Kết luận

Việc sử dụng ReactJs ban đầu đọc sẽ hơi khó hiểu vì nó tạo bằng các DOM ảo nhưng qua đó việc tùy biến của nó rất dễ dàng cũng như đặt tên dễ hiểu hơn. Code ở đây mình viết ở mức cơ bản để hiểu chứ chưa chuyên sâu, có dịp mình sẽ tìm hiểu sâu hơn và chia sẻ cùng các bạn. Và dưới đây video thành quả nghịch ngợm https://youtu.be/Hutp0hvPQ4c


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí