React.js xử lý update
- Chúng ta tiếp tục bài này với việc cập nhật, thay đổi dữ liệu.
- Cũng giống như insert, việc cập nhật dữ liệu cũng cần tiến hành ở phía client và server. Ta lần lượt tiến hành các bước như sau:
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ả
- 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ả
- Để 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 trongcomponentWillMount
, 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
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:
- 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:
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
để khiid
của item trùng vớikey
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:
- 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ứcpost
.axios.post('/api/edit', newUpdate)
sử dụng Axios tạo phương thứcpost
, 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
và/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é.