1. Code
  2. JavaScript
  3. React

Tạo một Ứng dụng Blog bằng React, Phần 3: Thêm và Hiển thị Bài viết

Trong phần trước của loạt bài hướng dẫn này, bạn đã học cách cài đặt chức năng đăng ký và đăng nhập. Trong phần hướng dẫn này, bạn sẽ cài đặt trang chủ của người dùng và chức năng thêm và hiển thị các bài viết trên blog.
Scroll to top
This post is part of a series called Creating a Blogging App Using React.
Creating a Blogging App Using React, Part 2: User Sign-Up
Creating a Blogging App Using React, Part 4: Update & Delete Posts

Vietnamese (Tiếng Việt) translation by Dai Phong (you can also view the original English article)

Trong phần trước của loạt bài hướng dẫn này, bạn đã học cách cài đặt chức năng đăng ký và đăng nhập. Trong phần hướng dẫn này, bạn sẽ cài đặt trang chủ của người dùng và chức năng thêm và hiển thị các bài viết trên blog.

Bắt đầu

Hãy bắt đầu bằng cách nhân bản mã nguồn từ phần đầu của bài hướng dẫn.

1
https://github.com/royagasthyan/ReactBlogApp-SignUp

Một khi thư mục đã được nhân bản, hãy chuyển đến thư mục của dự án và cài đặt các phụ thuộc cần thiết.

1
cd ReactBlogApp-SignUp
2
npm install

Khởi động máy chủ Node.js và ứng dụng của bạn sẽ chạy tại địa chỉ http://localhost:7777/index.html#/.

Tạo Trang chủ của Người dùng

Một khi người dùng đăng nhập vào trong ứng dụng, bạn cần phải kiểm tra các thông tin đăng nhập của người dùng và, nếu hợp lệ, tạo một session. Để sử dụng session trong một ứng dụng Node.js, bạn cần phải cài đặt express-session bằng Node Package Manager (npm).

1
 npm install express-session --save

Yêu cầu (require) express-session trong tập tin app.js.

1
var session = require('express-session');

Để sử dụng session, bạn cần phải đặt một session secret.

1
app.use(session({secret: 'my-secret'}));

Bây giờ hãy định nghĩa một biến được gọi là sessions trong phạm vi toàn cục.

1
var sessions

Gán biến sessions trong phương thức /signin sử dụng tham số yêu cầu.

1
sessions=req.session;

Sử dụng biến sessions, bạn lưu giữ tên người dùng đã đăng nhập bên trong session.

1
sessions.username = user_name;

Tạo một tập tin đặt tên là home.html bên trong thư mục html trong ứng dụng. Nó trông như sau:

1
<!DOCTYPE html>
2
<html lang="en">
3
  <head>
4
    <meta charset="utf-8">
5
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
    <meta name="viewport" content="width=device-width, initial-scale=1">
7
    <meta name="description" content="">
8
    <meta name="author" content="">
9
10
    <title>React Blog App</title>
11
    <link href="bootstrap.min.css" rel="stylesheet">
12
    <link href="jumbotron-narrow.css" rel="stylesheet">
13
14
    
15
  </head>
16
17
  <body>
18
19
    <div class="container">
20
      <div class="header clearfix">
21
        <nav>
22
          <ul class="nav nav-pills pull-right">
23
            <li role="presentation" class="active"><a href="#">Home</a></li>
24
            <li role="presentation"><a href="#">Add</a></li>
25
            <li role="presentation"><a href="#">Logout</a></li>
26
          </ul>
27
        </nav>
28
        <h3 class="text-muted">React Blog App</h3>
29
      </div>
30
31
      <div class="jumbotron">
32
       <div class="list-group"> <a href="#" class="list-group-item active"> <h4 class="list-group-item-heading">List group item heading</h4> <p class="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p> </a> <a href="#" class="list-group-item"> <h4 class="list-group-item-heading">List group item heading</h4> <p class="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p> </a> <a href="#" class="list-group-item"> <h4 class="list-group-item-heading">List group item heading</h4> <p class="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p> </a> </div>
33
      </div>
34
35
      
36
      <footer class="footer">
37
        <p>&copy; 2016 Company, Inc.</p>
38
      </footer>
39
40
    </div> 
41
  </body>
42
</html>

Tạo một route gọi là /home dùng để hiển thị trang chủ cho người dùng hợp lệ.

1
app.get('/home', function (req, res) {
2
  if(sessions && sessions.username){
3
    res.sendFile(__dirname + '/html/home.html');
4
  }
5
  else{
6
    res.send('unauthorized');
7
  }
8
})

Như đã thấy trong đoạn code ở trên, khi người dùng được chuyển hướng đến route /home, nếu sessionssessions.username tồn tại, thì trang chủ sẽ được hiển thị.

Hãy sửa đổi phương thức signin để gửi một phản hồi thành công khi người dùng được xác thực thành công.

1
app.post('/signin', function (req, res) {
2
  sessions=req.session;
3
  var user_name=req.body.email;
4
  var password=req.body.password;
5
  user.validateSignIn(user_name,password,function(result){
6
    if(result){
7
      sessions.username = user_name;
8
      res.send('success');
9
    }
10
  });
11
})

Phản hồi thành công ở trên được phân tích ở phía React và, nếu thành công, người dùng được chuyển hướng đến rout /home. Trong tập tin main.jsx, bên trong thành phần Signin bên trong phương thức signIn, hãy sửa đổi code để chuyển hướng đến trang chủ.

1
signIn(){
2
  axios.post('/signin', {
3
    email: this.state.email,
4
    password: this.state.password
5
  })
6
  .then(function (response) {
7
    if(response.data == 'success'){
8
      window.location.assign('http://localhost:7777/home')
9
    }
10
  })
11
  .catch(function (error) {
12
    console.log(error);
13
  });
14
}

Lưu các thay đổi ở trên và khởi động lại máy chủ Node. Đăng nhập bằng tên người dùng và mật khẩu hợp lệ, và bạn sẽ được chuyển hướng đến trang chủ.

React Blog App - User Home PageReact Blog App - User Home PageReact Blog App - User Home Page

Sửa đổi chức năng hiển thị bài viết ở trên thành một thành phần React. Tạo một tập tin đặt tên là home.jsx. Bên trong tập tin home.jsx, tạo một thành phần React gọi là ShowPost dùng để hiển thị danh sách bài viết trên blog. Di chuyển HTML tĩnh bên trong phương thức render của thành phần React. Thành phần ShowPost sẽ trông như sau:

1
class ShowPost extends React.Component {
2
    constructor(props) {
3
      super(props);
4
    }
5
    
6
    render() {
7
      return (
8
          <div className="list-group"> 
9
            <a href="#" className="list-group-item active">
10
              <h4 className="list-group-item-heading">List group item heading</h4>

11
              <p className="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p>

12
            </a>

13
            <a href="#" className="list-group-item">
14
              <h4 className="list-group-item-heading">List group item heading</h4>

15
              <p className="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p>

16
            </a> 

17
            <a href="#" className="list-group-item">
18
              <h4 className="list-group-item-heading">List group item heading</h4>

19
              <p className="list-group-item-text">Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius blandit.</p>

20
            </a> 

21
          </div>

22
      )
23
    }
24
}

Thay đổi trang home.html để bao gồm các thư viện React cần thiết. Dưới đây là trang home.html đã được sửa đổi:

1
<!DOCTYPE html>
2
<html lang="en">
3
4
<head>
5
    <meta charset="utf-8">
6
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
7
    <meta name="viewport" content="width=device-width, initial-scale=1">
8
    <meta name="description" content="">
9
    <meta name="author" content="">
10
11
    <title>React Blog App</title>
12
    <link href="bootstrap.min.css" rel="stylesheet">
13
    <link href="jumbotron-narrow.css" rel="stylesheet">
14
    <script src="https://fb.me/react-15.1.0.js"></script>
15
    <script src="https://fb.me/react-dom-15.1.0.js"></script>
16
    <script src="https://npmcdn.com/react-router@3.0.2/umd/ReactRouter.min.js"></script>
17
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
18
    <script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
19
20
</head>
21
22
<body>
23
24
    <div class="container">
25
        <div class="header clearfix">
26
            <nav>
27
                <ul class="nav nav-pills pull-right">
28
                    <li role="presentation" class="active"><a href="#">Home</a></li>
29
                    <li role="presentation"><a href="#">Add</a></li>
30
                    <li role="presentation"><a href="#">Logout</a></li>
31
                </ul>
32
            </nav>
33
            <h3 class="text-muted">React Blog App</h3>
34
        </div>
35
36
        <div id="app" class="jumbotron">
37
38
        </div>
39
40
41
        <footer class="footer">
42
            <p>&copy; 2016 Company, Inc.</p>
43
        </footer>
44
45
    </div>
46
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
47
    <script type="text/babel" src="home.jsx">
48
    </script>
49
</body>
50
51
</html>

Như đã thấy trong code HTML ở trên, div container đã được đặt tên là app, bên trong đó các thành phần của React sẽ được hiển thị.

Lưu các thay đổi ở trên và khởi động lại máy chủ Node. Đăng nhập vào ứng dụng blog và, một khi ở trên trang chủ, bạn sẽ thấy thành phần ShowPost được kết xuất.

Bây giờ bạn cần điền các giá trị trong danh sách bài viết một cách tự động. Trước khi làm vậy, hãy tạo một trang để thêm một bài viết. Khi nhấp vào liên kết Add ở trên, bạn cần hiển thị trang để thêm bài viết.

Thêm Thành phần React gọi là AddPost

Hãy tạo một thành phần React để thêm các bài viết trên blog. Nó sẽ bao gồm một hộp nhập tiêu đề và một ô nhập văn bản cho chủ đề. Trong home.jsx, hãy tạo một thành phần React đặt tên là AddPost để thêm các bài viết. Thành phần AddPost sẽ trông như sau:

1
class AddPost extends React.Component {
2
    render() {
3
      return (
4
        <div className="col-md-5">
5
          <div className="form-area">  
6
              <form role="form">
7
              <br styles="clear:both" />
8
                <div className="form-group">
9
                  <input type="text" className="form-control" id="title" name="title" placeholder="Title" required />
10
                </div>
11
               
12
                <div className="form-group">
13
                <textarea className="form-control" type="textarea" id="subject" placeholder="Subject" maxlength="140" rows="7"></textarea>
14
                </div>
15
                  
16
              <button type="button" id="submit" name="submit" className="btn btn-primary pull-right">Add Post</button>
17
              </form>
18
          </div>
19
        </div>
20
      )
21
    }
22
}

Khi người dùng nhập tiêu đề và chủ đề của bài viết, bạn cần phải xử lý các sự kiện thay đổi văn bản trong phần React. Thêm bộ xử lý (handler) sự kiện thay đổi sau đây vào thành phần AddPost.

1
handleTitleChange(e){
2
    this.setState({title:e.target.value})
3
}
4
handleSubjectChange(e){
5
    this.setState({body:e.target.value})
6
}

Thêm sự kiện on change vào code HTML của AddPost.

1
<div className="form-group">
2
  <input type="text" onChange={this.handleTitleChange} className="form-control" id="title" name="title" placeholder="Title" required />
3
</div>
4
5
<div className="form-group">
6
  <textarea className="form-control" onChange={this.handleSubjectChange} type="textarea" id="subject" placeholder="Subject" maxlength="140" rows="7"></textarea>
7
</div>

Liên kết các biến state và các sự kiện bên trong phương thức constructor của React.

1
constructor(props) {
2
  super(props);
3
  this.handleTitleChange = this.handleTitleChange.bind(this);
4
  this.handleSubjecChange = this.handleSubjectChange.bind(this);
5
  this.state = {
6
    title:'',
7
    subject:''
8
  };
9
}

Khi người dùng nhấp vào nút Add Post, bạn cần post tiêu đề và chủ đề từ giao diện người dùng React lên back-end Node.js để lưu nó vào cơ sở dữ liệu MongoDB. Tạo một phương pháp đặt tên là addPost trong thành phần AddPost để post tiêu đề và chủ đề đến trình xử lý yêu cầu Node.js. Phương thức addPost trong thành phần AddPost sẽ như sau:

1
addPost(){
2
  axios.post('/addPost', {
3
    title: this.state.title,
4
    subject: this.state.subject
5
  })
6
  .then(function (response) {
7
    console.log('response from add post is ',response);
8
    hashHistory.push('/')
9
  })
10
  .catch(function (error) {
11
    console.log(error);
12
  });
13
}

Như đã thấy trong đoạn code ở trên, bạn sử dụng axios để post các chi tiết của bài viết lên máy chủ Node.js.

Bây giờ bạn cần phải tạo một mô-đun post mà sẽ xử lý việc thêm và lấy về các chi tiết của bài viết. Hãy tạo một tập tin có tên là post.js trong thư mục của dự án. Trong tập tin post.js, xuất một phương thức addPost cái mà sẽ chèn thông tin chi tiết của bài viết vào cơ sở dữ liệu MongoDB. Yêu cầu (require) MongoClient và tạo phương thức addPost để chèn các thông tin chi tiết của bài viết vào trong cơ sở dữ liệu MongoDB. Tập tin post.js sẽ trông như sau:

1
var MongoClient = require('mongodb').MongoClient;
2
var assert = require('assert');
3
var url = 'mongodb://localhost:27017/Blog';
4
5
module.exports = {
6
    addPost: function(title, subject, callback){
7
  	MongoClient.connect(url, function(err, db) {
8
		  	db.collection('post').insertOne( {
9
				"title": title,
10
				"subject": subject
11
			},function(err, result){
12
				assert.equal(err, null);
13
		    	console.log("Saved the blog post details.");
14
		    	if(err == null){
15
		    		callback(true)
16
		    	}
17
		    	else{
18
		    		callback(false)
19
		    	}
20
			});
21
		});
22
	}
23
}
24
25

Như đã thấy trong đoạn code ở trên, bạn kết nối đến cơ sở dữ liệu MongoDB bằng trình kết nối và chèn một bản ghi. Một khi thao tác được thực thi, bạn kiểm tra lỗi nếu có, và trả về trạng thái cho hàm callack.

Bên trong tập tin app.js, tạo một trình xử lý yêu cầu gọi là addPost cái mà sẽ gọi phương thức addPost từ post.js. Nó sẽ trông như sau:

1
app.post('/addpost', function (req, res) {
2
  var title = req.body.title;
3
  var subject = req.body.subject;
4
  post.addPost(title, subject ,function(result){
5
    res.send(result);
6
  });
7
})

Lưu các thay đổi ở trên và khởi động lại máy chủ Node.js. Đăng nhập vào ứng dụng, nhấp vào liên kết Add, và nhập các chi tiết để thêm một bài viết. Sau khi hoàn tất, nhấp vào nút Add Post và các chi tiết sẽ được lưu trong cơ sở dữ liệu MongoDB.

Add Post ScreenAdd Post ScreenAdd Post Screen

Hiển thị Thành phần Post

Trước tiên, bạn cần lấy về các chi tiết của bài viết đã lưu từ MongoDB. Bên trong tập tin post.js, hãy tạo một phương thức gọi là getPost dùng để lấy thông tin chi tiết về bài viết. Nó sẽ trông như sau:

1
getPost: function(callback){
2
	MongoClient.connect(url, function(err, db){
3
		 db.collection('post', function (err, collection) {
4
	        collection.find().toArray(function (err, list) {
5
	            callback(list);
6
	        });
7
	     });
8
	})
9
}

Đoạn code ở trên lấy thông tin chi tiết từ collection của MongoDB, chuyển đổi nó thành một danh sách và gửi nó ngược trở lại hàm callback. Trong tập tin home.jsx, bên trong thành phần ShowPost, lấy các chi tiết của bài viết bên trong phương thức componentDidMount. Nó sẽ trông như sau:

1
componentDidMount(){
2
  var self = this;
3
4
  axios.post('/getPost', {
5
   
6
  })
7
  .then(function (response) {
8
    
9
  })
10
  .catch(function (error) {
11
    console.log('error is ',error);
12
  });
13
}

Đoạn code ở trên tạo một yêu cầu post đến phương thức /getPost của máy chủ Node.js cái mà sẽ gọi đến phương thức getPost trong tập tin post.js. Dưới đây là phương thức /getPost trong tập tin app.js.

1
app.post('/getpost', function (req, res) {
2
  post.getPost(function(result){
3
    res.send(result);
4
  });
5
})

Một khi các chi tiết của bài viết đã được lấy ra bên trong hàm callback thành công của axios, hãy giữ các chi tiết bên trong một mảng state. Khai báo một biến được gọi là posts bên trong constructor của ShowPost.

1
constructor(props) {
2
  super(props);
3
  this.state = {
4
    posts:[]
5
  };
6
}

Trong hàm callback thành công của cuộc gọi ajax axios, hãy thiết lập biến state như sau:

1
self.setState({posts:response.data})

Một khi bạn đã có các chi tiết về bài viết, bạn cần tự động tạo HTML cần thiết bên trong phương thức render của thành phần React. Nó sẽ trông như sau:

1
render() {
2
  return (
3
      <div className="list-group"> 
4
5
        {
6
          this.state.posts.map(function(post,index) {
7
             return <a href="#" key={index} className="list-group-item active">
8
                      <h4 className="list-group-item-heading">{post.title}</h4>

9
                      <p className="list-group-item-text">{post.subject}</p>

10
                    </a>

11
          })
12
        }
13
        
14
      </div>

15
  )
16
}

Đoạn code ở trên lặp qua biến trạng thái posts và tạo HTML động. Lưu các thay đổi ở trên và khởi động lại máy chủ Node.js. Đăng nhập vào ứng dụng blog và tạo một vài bài viết trên blog bằng nút Add trên trang chủ. Một khi các bài viết đã được thêm vào, chúng sẽ được hiển thị trên trang chủ.

Display Post PageDisplay Post PageDisplay Post Page

Tóm tắt

Trong bài hướng dẫn này, bạn đã học được cách tạo ra các thành phần React để thêm và hiển thị các bài viết trên blog. Trong phần tiếp theo của loạt bài hướng dẫn này, bạn sẽ học cách thêm chức năng xóa và cập nhật bài viết trên blog.

Hãy cho tôi biết những suy nghĩ của bạn về hướng dẫn này trong phần bình luận bên dưới nhé. Mã nguồn từ hướng dẫn này có sẵn trên GitHub.