React.js xử lý update

React.js xử lý update

Tạo button click mở modal

  • Trước tiên ta cần tạo button bên trong file /client/src/App.js như sau:
<ul>
  {this.state.news.map(item => (
    <li key={item.id}>
      <h2>{item.title}</h2>
      <div>{item.description}</div>
       <button onClick={}>Edit</button>
    </li>
  ))}
</ul>

Kết quả

React.js MySQL update

  • Như đã nói trước đây, với React chúng ta hoàn toàn có thể sử dụng các component đã được tạo sẵn, do đó để sử dụng modal, thay vì viết mới lại hoàn toàn, ta chỉ việc cài đặt và sử dụng, chúng ta tiến hành cài đặt bằng lệnh sau:

Do hoạt động ở client nên ta sẽ cài đặt tại /client/

cd client
npm install react-modal

Kết quả

React.js MySQL update

  • Để sử dụng được modal, ta cần khai báo, xử lý click mở modal, ta thêm nội dung cho /client/src/App.js như sau (chú ý là code bên dưới đã bỏ một số nội dung không liên quan tới việc update rồi nhé, ví dụ như nội dung code của phần insert).
import React, { Component } from 'react';
import axios from 'axios';
import Modal from 'react-modal';

class App extends Component {
  constructor (props) {
    super(props);
    this.state = {
      modalIsOpen: false,
      news: []
    }
  };

  componentDidMount() {
    axios.get('/api/news')
         .then(res => {
            const news = res.data;
            this.setState({ news: news.news });
          })
         .catch(error => console.log(error));
  };

  handleInputChange = (event) => {
    const target = event.target;
    const value = target.value;
    const name = target.name;
    this.setState({
      [name]: value
    });
  };

  componentWillMount() {
    Modal.setAppElement('body');
  };

  openModal = () => {
    this.setState({
      modalIsOpen: true,
    });
  };

  closeModal = () => {
    this.setState({
      modalIsOpen: false
    });
  };

  render() {
    return(
      <div>
        <ul>
          {this.state.news.map(item => (
            <li key={item.id}>
              <h2>{item.title}</h2>
              <div>{item.description}</div>
               <button onClick={() => this.openModal()}>Edit</button>
            </li>
          ))}
        </ul>

        <Modal
          isOpen={this.state.modalIsOpen}
          onRequestClose={this.closeModal}>
          <button onClick={this.closeModal}>Close</button>
          <div>Nội dung Modal</div>
        </Modal>
      </div>
    )
  }
};

export default App;
  • import Modal from 'react-modal' - khai báo sử dụng modal.
  • modalIsOpen: false - khai báo ban đầu modal không hiển thị.
  • Modal.setAppElement('body') - được viết bên trong componentWillMount, mục đích làm cho thành phần form xuất hiện trước, để khi đó mới lấy được dữ liệu khi click button.
  • openModal - nơi xử lý hành động khi modal được mở.
  • closeModal - nơi xử lý hành động khi modal được đóng.
  • <Modal> - đây là khu vực hiển thị nội dung modal.
  • Tới đây thì ta đã tạo xong nội dung modal rồi, xem lại trình duyệt lúc này ta sẽ xem được kết quả.

Kết quả khi click button Edit

React.js MySQL update

Tạo form lấy dữ liệu thông qua id

  • Bên trên ta đã tạo được modal, tiếp theo ta cần viết một form update sao cho khi click vào button Edit thì sẽ hiển thị nội dung form update, ta làm như sau:

/client/src/App.js

Form được viết bên trong nội dung modal.

<Modal
  isOpen={this.state.modalIsOpen}
  onRequestClose={this.closeModal}>
  <button onClick={this.closeModal}>Close</button>
  
  <form>
    <table>
      <tbody>
        <tr>
          <th><label>Title</label></th>
          <td>
            <input
              type="text"
              name="title"
              value="" />
          </td>
        </tr>

        <tr>
          <th><label>Description</label></th>
          <td>
            <textarea
              name="description"
              value="" />
          </td>
        </tr>

        <tr>
          <th><label>Content</label></th>
          <td>
            <textarea
              name="content"
              value="" />
          </td>
        </tr>
      </tbody>
    </table>
    <button type="submit">Edit</button>
  </form>
</Modal>
  • Khi này click button Edit, ta sẽ thấy kết quả sau:

React.js MySQL update

  • Ta sẽ viết tiếp nội dung, sao cho khi click vào button Edit của item nào thì nội dung của item đó sẽ hiển thị trong modal tương ứng.
  • Ta viết lại nội dung /client/src/App.js như sau:
import React, { Component } from 'react';
import axios from 'axios';
import Modal from 'react-modal';

class App extends Component {
  constructor (props) {
    super(props);
    this.state = {
      modalIsOpen: false,
      news: []
    }
  };

  componentDidMount() {
    axios.get('/api/news')
         .then(res => {
            const news = res.data;
            this.setState({ news: news.news });
          })
         .catch(error => console.log(error));
  };

  handleInputChange = (event) => {
    const target = event.target;
    const value = target.value;
    const name = target.name;
    this.setState({
      [name]: value
    });
  };

  componentWillMount() {
    Modal.setAppElement('body');
  };

  openModal = (item) => {
    this.setState({
      modalIsOpen: true,
      id: item.id,
      title: item.title,
      description: item.description,
      content: item.content
    });
  };

  closeModal = () => {
    this.setState({
      modalIsOpen: false
    });
  };

  render() {
    return(
      <div>
        <ul>
          {this.state.news.map(item => (
            <li key={item.id}>
              <h2>{item.title}</h2>
              <div>{item.description}</div>
               <button onClick={() => this.openModal(item)}>Edit</button>
            </li>
          ))}
        </ul>

        <Modal
          isOpen={this.state.modalIsOpen}
          onRequestClose={this.closeModal}>
          <button onClick={this.closeModal}>Close</button>
          <form>
            <table>
              <tbody>
                <tr>
                  <th><label>Title</label></th>
                  <td>
                    <input
                      type="text"
                      name="title"
                      value={this.state.title} />
                  </td>
                </tr>

                <tr>
                  <th><label>Description</label></th>
                  <td>
                    <textarea
                      name="description"
                      value={this.state.description} />
                  </td>
                </tr>

                <tr>
                  <th><label>Content</label></th>
                  <td>
                    <textarea
                      name="content"
                      value={this.state.content} />
                  </td>
                </tr>
              </tbody>
            </table>
            <button type="submit">Edit</button>
          </form>
        </Modal>
      </div>
    )
  }
};

export default App;
  • Khi này click button Edit của item nào thì nội dung của item đó sẽ được load bên trong modal, ta sẽ thấy kết quả sau:

React.js MySQL update

Xử lý thay đổi dữ liệu ở phía client

  • Tiếp theo ta cần xử lý sao cho khi submit thay đổi dữ liệu ở modal, thì nội dung ở client thay đổi theo, tất nhiên lúc này dữ liệu ở MySQL vẫn chưa thay đổi.
  • Ta điều chỉnh lại nội dung /client/src/App.js như sau:
import React, { Component } from 'react';
import axios from 'axios';
import Modal from 'react-modal';

class App extends Component {
  constructor (props) {
    super(props);
    this.state = {
      modalIsOpen: false,
      news: [],
      id: '',
      title: '',
      description: '',
      content: ''
    }
  };

  componentDidMount() {
    axios.get('/api/news')
         .then(res => {
            const news = res.data;
            this.setState({ news: news.news });
          })
         .catch(error => console.log(error));
  };

  handleInputChange = (event) => {
    const target = event.target;
    const value = target.value;
    const name = target.name;
    this.setState({
      [name]: value
    });
  };

  componentWillMount() {
    Modal.setAppElement('body');
  };

  openModal = (item) => {
    this.setState({
      modalIsOpen: true,
      id: item.id,
      title: item.title,
      description: item.description,
      content: item.content
    });
  };

  closeModal = () => {
    this.setState({
      modalIsOpen: false
    });
  };

  handleEditSubmit = (event) => {
    event.preventDefault();

    let key = this.state.id;
    this.setState(prevState => ({
      news: prevState.news.map(
        elm => elm.id === key ? {
          ...elm,
          title: this.state.title,
          description: this.state.description,
          content: this.state.content
        }: elm
      )
    }))
  };

  render() {
    return(
      <div>
        <ul>
          {this.state.news.map(item => (
            <li key={item.id}>
              <h2>{item.title}</h2>
              <div>{item.description}</div>
               <button onClick={() => this.openModal(item)}>Edit</button>
            </li>
          ))}
        </ul>

        <Modal
          isOpen={this.state.modalIsOpen}
          onRequestClose={this.closeModal}>
          <button onClick={this.closeModal}>Close</button>
          <form onSubmit={this.handleEditSubmit}>
            <table>
              <tbody>
                <tr>
                  <th><label>Title</label></th>
                  <td>
                    <input
                      type="text"
                      name="title"
                      value={this.state.title} 
                      onChange={this.handleInputChange} />
                  </td>
                </tr>

                <tr>
                  <th><label>Description</label></th>
                  <td>
                    <textarea
                      name="description"
                      value={this.state.description} 
                      onChange={this.handleInputChange} />
                  </td>
                </tr>

                <tr>
                  <th><label>Content</label></th>
                  <td>
                    <textarea
                      name="content"
                      value={this.state.content} 
                      onChange={this.handleInputChange} />
                  </td>
                </tr>
              </tbody>
            </table>
            <button type="submit">Edit</button>
          </form>
        </Modal>
      </div>
    )
  }
};

export default App;
  • this.state = {} tại khai báo cho state, ta thêm các thuộc tính liên quan, để nhận các giá trị setState từ form.
  • handleEditSubmit function dùng để xử lý nội dung form.
  • key = this.state.id key này dùng để nhận diện item nào được xử lý cập nhật nội dung mới.
  • Ta sử dụng news: prevState.news.map để khi id của item trùng với key thì sẽ tiến hành thay đổi, ngược lại thì giữ nguyên không thay đổi.
  • onChange={this.handleInputChange} các thành phần form khi được thay đổi, thì ta sẽ lấy được giá trị các thành phần tương ứng.

Vậy là ta đã hoàn thành việc thay đổi cập nhật nội dung cho client, bạn thử thay đổi sẽ thấy kết quả sau:

React.js MySQL update

  • Hiện tại chỉ mới cập nhật được phía client thôi, nên khi reload lại trình duyệt thì kết quả sẽ như cũ, để thực hiện thay đổi đồng thời MySQL ta làm như bên dưới nhé.

Xử lý thay đổi dữ liệu vào MySQL

  • Bước xử lý này tương tự như insert sản phẩm, ta cần sử dụng Axios điều khiển post dữ liệu, và dùng API xử lý thay đổi dữ liệu MySQL.
  • Ta lần lượt chỉnh 2 file sau:
    • /client/src/App.js xử lý dữ liệu post thông qua Axios.
    • /app.js nhận và xử lý dữ liệu, sau đó insert vào MySQL.

Viết lại nội dung handleEditSubmit của /client/src/App.js như sau:

handleEditSubmit = (event) => {
  event.preventDefault();

  const newUpdate = {
      id: this.state.id,
      title: this.state.title,
      description: this.state.description,
      content: this.state.content
  };

  axios.post('/api/edit', newUpdate)
    .then(res => {
      let key = this.state.id;
      this.setState(prevState => ({
        news: prevState.news.map(
          elm => elm.id === key? {
            ...elm,
            title: this.state.title,
            description: this.state.description,
            content: this.state.content
          }: elm
        )
      }))
    })
    .catch(error => console.log(error));
};
  • const newUpdate khai báo giá trị để truyền theo phương thức post.
  • axios.post('/api/edit', newUpdate) sử dụng Axios tạo phương thức post, truyền giá trị newUpdate kèm theo.
  • Viết nội dung cập nhật client bên trong Axios để đảm bảo dữ liệu được gửi mới xử lý client.

viết thêm nội dung xử lý cho cập nhật dữ liệu nhận được bên trong /app.js

app.post('/api/edit', (req, res) => {
  var sql = "UPDATE news SET "
          +   "title='"+req.body.title+"',"
          +   "description='"+req.body.description+"',"
          +   "content='"+req.body.content+"'"
          + "WHERE id='"+req.body.id+"'";
  connection.query(sql, function(err, results) {
    if (err) throw err;
    res.json({news: results});
  });
});
  • Nội dung trên không có gì đặt biệt nhe, chỉ là lấy giá trị post từ client, tiến hành update vào MySQL, xong trả về route /api/edit.
  • Vậy là xong rồi đó, chạy lại npm run dev, sau đó thử thay đổi nội dung và reload lại trang, sẽ thấy nội dung thay đổi vừa cập nhật ở client, vừa thay đổi MySQL.

Tổng kết

  • Sau khi hoàn nội dung bài học, ta sẽ tạo được 2 file /client/src/App.js/app.js như sau:

/client/src/App.js

Code bao gồm phần insert.

import React, { Component } from 'react';
import axios from 'axios';
import Modal from 'react-modal';

class App extends Component {
  constructor (props) {
    super(props);
    this.state = {
      modalIsOpen: false,
      news: [],
      id: '',
      title: '',
      description: '',
      content: ''
    }
  };

  componentDidMount() {
    axios.get('/api/news')
         .then(res => {
            const news = res.data;
            this.setState({ news: news.news });
          })
         .catch(error => console.log(error));
  };

  handleInputChange = (event) => {
    const target = event.target;
    const value = target.value;
    const name = target.name;
    this.setState({
      [name]: value
    });
  };

  handleInsertSubmit = (event) => {
    event.preventDefault();

    const newItem = {
        id: '',
        title: this.state.title,
        description: this.state.description,
        content: this.state.content
    };

    axios.post('/api/insert', newItem)
      .then(res => {
        let news = this.state.news;
        news = [newItem,...news];
        this.setState({ news: news });
      })
      .catch(error => console.log(error));
  };

  componentWillMount() {
    Modal.setAppElement('body');
  };

  openModal = (item) => {
    this.setState({
      modalIsOpen: true,
      id: item.id,
      title: item.title,
      description: item.description,
      content: item.content
    });
  };

  closeModal = () => {
    this.setState({
      modalIsOpen: false
    });
  };

  handleEditSubmit = (event) => {
    event.preventDefault();

    const newUpdate = {
      id: this.state.id,
      title: this.state.title,
      description: this.state.description,
      content: this.state.content
  };

  axios.post('/api/edit', newUpdate)
    .then(res => {
      let key = this.state.id;
      this.setState(prevState => ({
        news: prevState.news.map(
          elm => elm.id === key? {
            ...elm,
            title: this.state.title,
            description: this.state.description,
            content: this.state.content
          }: elm
        )
      }))
    })
    .catch(error => console.log(error));
  };

  render() {
    return(
      <div>
        <h2>Add an item</h2>
        <form onSubmit={this.handleInsertSubmit}>
          <table>
            <tbody>
              <tr>
                <th><label>Title</label></th>
                <td>
                  <input
                    name="title"
                    type="text"
                    onChange={this.handleInputChange} />
                </td>
              </tr>

              <tr>
                <th><label>Description</label></th>
                <td>
                  <textarea
                    name="description"
                    onChange={this.handleInputChange} />
                </td>
              </tr>

              <tr>
                <th><label>Content</label></th>
                <td>
                  <textarea
                    name="content"
                    onChange={this.handleInputChange} />
                </td>
              </tr>
            </tbody>
          </table>

          <button type="submit">Submit</button>
        </form>

        <hr />

        <ul>
          {this.state.news.map(item => (
            <li key={item.id}>
              <h2>{item.title}</h2>
              <div>{item.description}</div>
               <button onClick={() => this.openModal(item)}>Edit</button>
            </li>
          ))}
        </ul>

        <Modal
          isOpen={this.state.modalIsOpen}
          onRequestClose={this.closeModal}>
          <button onClick={this.closeModal}>Close</button>
          <form onSubmit={this.handleEditSubmit}>
            <table>
              <tbody>
                <tr>
                  <th><label>Title</label></th>
                  <td>
                    <input
                      type="text"
                      name="title"
                      value={this.state.title} 
                      onChange={this.handleInputChange} />
                  </td>
                </tr>

                <tr>
                  <th><label>Description</label></th>
                  <td>
                    <textarea
                      name="description"
                      value={this.state.description} 
                      onChange={this.handleInputChange} />
                  </td>
                </tr>

                <tr>
                  <th><label>Content</label></th>
                  <td>
                    <textarea
                      name="content"
                      value={this.state.content} 
                      onChange={this.handleInputChange} />
                  </td>
                </tr>
              </tbody>
            </table>
            <button type="submit">Edit</button>
          </form>
        </Modal>
      </div>
    )
  }
};

export default App;

/app.js

const express = require('express');
const mysql = require('mysql');
const app = express();
const bodyParser = require('body-parser');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'reactUser',
  password: '1234567',
  database: 'reactmysql'
});

connection.connect(function(err){
  (err) ? console.log(err) : console.log(connection);
});

app.get('/api/news', (req, res) => {
  var sql = "SELECT * FROM news ORDER BY id DESC";
  connection.query(sql, function(err, results) {
    if (err) throw err;
    res.json({news: results});
  });
});

app.post('/api/insert', function(req, res) {
  var sql = "INSERT "
          + "INTO news(title,description,content) "
          + "VALUES('"
          +   req.body.title+ "','" 
          +   req.body.description + "','" 
          +   req.body.content+"')";
  connection.query(sql, function (err, results) {
    if(err) throw err;
    res.json({news: results});
  });
});

app.post('/api/edit', (req, res) => {
  var sql = "UPDATE news SET "
          +   "title='"+req.body.title+"',"
          +   "description='"+req.body.description+"',"
          +   "content='"+req.body.content+"'"
          + "WHERE id='"+req.body.id+"'";
  connection.query(sql, function(err, results) {
    if (err) throw err;
    res.json({news: results});
  });
});
 
app.listen(4000, () => console.log('App listening on port 4000'));
  • Nội dung download sẽ được chia sẻ ở bài học sau nhé.
  • Bài học tiếp theo sẽ hướng dẫn các bạn cách xóa một item bất kỳ, cùng theo dõi nhé.