---
title: "Hướng dẫn clone instagram với React JS và Firebase phần 2."
description: "Trong phần 1 của series này, chúng ta tiến hành setup một project ReactJS bằng câu lệnh create-react-app,đăng ký và tạo app trên firebase để có thể sử dụng và lưu trữ data. Trong phần 2 này, chúng ta sẽ tạo header cho nó và tạo component post để hiển thị bài đăng nhé 😉. Nào bắt đầu thôi 😁!"
canonical: "https://200lab.io/blog/clone-instagram-voi-react-js-va-firebase-phan-2"
published: "2021-09-27T00:28:56Z"
updated: "2026-08-21T07:17:55Z"
authors: ["TỪ QUỐC HƯNG"]
tags: ["Javascript"]
reading_minutes: 9
access: "public"
---

Trong phần 1 của series này, chúng ta tiến hành setup một project ReactJS bằng câu lệnh `create-react-app`, đăng ký và tạo app trên firebase để có thể sử dụng và lưu trữ data. Trong phần 2 này, chúng ta sẽ tạo header cho nó và tạo component post để hiển thị bài đăng nhé 😉. Nào bắt đầu thôi 😁!

## I. Tạo header cho app.

Đầu tiên, run project của chúng ta lên bằng câu lệnh `npm start`, sau đó vào `App.js` và xóa hết các đoạn code demo của React đi nhé, nhớ là xóa code trong thẻ `<div id="app"></div>`, `import logo from "./logo.svg";` thôi nhé 🤣, trong `App.css` ta cũng xóa hết đi.

Trong folder `src` ta tạo một folder `components` đây là nơi chúng ta dùng để lưu trữ các **component **của chúng ta về sau, như hình dưới:

![](https://assets.200lab.io/images/2024/12/05/img-01-folder-components-1-359ed1bb1530520d8fd8.webp)

file `App.js` là file gốc, chứa các component cha để render ra một page hoàn chỉnh. Cấu trúc trong file `App.js` của chúng ta trong bài này sẽ như sau:

![](https://assets.200lab.io/images/2024/12/05/img-02-structure-app-js-ad6f62a66bd0bbfbaf64.webp)

Trong folder `components` ta tạo một folder với tên là `Header` và trong nó tạo thêm 2 file là `Header.jsx` và `Style-Header.css`. Chúng ta sẽ code phần **header **và style cho nó trong hai file này, sau đó ta sẽ `import` nó vào trong `App.js` và sử dụng thôi 😁.

![](https://assets.200lab.io/images/2024/12/05/img-03-structure-header-component-d78181b1d74d24ff78dc.webp)

Trong `Header.jsx` ta code như sau:

```
import React from "react";
import "./Style-Header.css";

export default function Header() {
  return (
    <div className="container">
            <div className="header">
                <div className="header__logo">
                    <img
                    src="https://www.instagram.com/static/images/web/mobile_nav_type_logo.png/735145cfe0a4.png"
                    alt="Logo"
                    />
                </div>
                <div className="header__search">
                    <input type="text" placeholder="Tìm kiếm"/>
                    <i className='bx bx-search-alt-2' ></i>
                </div>
                <div className="header__login">
                    <button className="btn btn-login">Login</button>
                </div>
            </div>
        </div>
  );
}

```

`import` component Header vào `App.js` như hình.

![](https://assets.200lab.io/images/2024/12/05/img-06-import-header-to-app-001aced2119a29f63563.webp)

Các **icon **mình sử dụng thằng **Boxicon**, các bạn có thể [vào đây](<https://boxicons.com/usage>) để lấy link css và thêm vào file `index.html` ở folder **public **nhé 😉

Phần logo bạn có thể sử dụng luôn link ảnh của **Instagram **chính chủ nha 😁, nhớ phải `import` css của **header **vào trong component Header nữa nhé. Sau khi xong ta sẽ được UI cơ bản như hình.

![](https://assets.200lab.io/images/2024/12/05/img-04-header-component-jsx-989f0e0974c884ceadb7.webp)

Chúng ta sẽ style cho phần **header **nào 😉, trong file `Style-Header.css` ta thêm css cho nó như sau:

```css
.container {
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #fff;
    height: 54px;
    position: fixed;
    top: 0;
    width: 100%;
    z-index: 3;
    border-bottom: 1px solid #dbdbdb;
}

.header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 54px;
    max-width: 975px;
    padding: 0 20px;
    width: 100%;
    z-index: 10;
}

.header__logo img {
    object-fit: contain;
}

.header__search {
    display: flex;
    align-items: center;
    height: 28px;
    flex: 0 1 auto;
    min-width: 125px;
    width: 215px;
    -webkit-box-flex: 0;
    position: relative;
}

.header__search input {
    font-size: 14px;
    border: solid 1px #dbdbdb;
    outline: none;
    padding: 3px 10px 3px 26px;
    z-index: 2;
    color: #262626;
    background-color: #fafafa;
}

.header__search i.bx-search-alt-2 {
    position: absolute;
    z-index: 15;
    padding-left: 10px;
}

.btn {
    padding: 5px 15px;
    border: 1px solid transparent;
    border-radius: 4;
    cursor: pointer;
}

.btn-login {
    background-color: #0095f6;
    color: #fff;
    transition: all 0.5s ease;
    font-weight: 600;
}

.btn-login:hover {
    opacity: 0.8;
}
```

_Style-Header.css_

Ta sử dụng `App.css` làm file css chung cho toàn bộ page của chúng ta, tức là có cái style nào mà dùng đi dùng lại hoặc dùng cho toàn bộ trang thì ta quăng ở đó 🤭.

```css
body {
    background-color: #fafafa;
}
```

_App.css_

Đây là thành quả của chúng ta 😁.

![](https://assets.200lab.io/images/2024/12/05/img-05-header-component-jsx-add-css-4e3154c0f2471c2b6bfe.webp)

## II. Tạo bài post cho app

Các bạn cũng có thể thấy là trong instagram có rất nhiều bài post theo thứ tự mới nhất đến cũ nhất, mỗi bài post như vậy ta gọi là một **PostItem**. Trong phần này ta sẽ tạo một **PostItem** để hiển thi một post mẫu nhé 😉.

![](https://assets.200lab.io/images/2024/12/05/img-07-post-item-exam-3-8bc80d1e892379b5f39a.webp)

Đây là một **PostItem **mẫu mình trích từ instagram của mình, những phần mình khoanh đỏ trong hình ảnh chính là những thứ mà chúng ta sẽ làm nhé còn lại chúng ta chưa quan tâm lúc này.

Trong folder `components` tạo thêm một folder tên **PostItem **và trong nó tạo thêm 2 file `PostItem.jsx` và `Style-PostItem.css`. Tạo xong nhớ **implement code **và `import` file css vào nhé 😁.

Cấu trúc của một bài Post như sau:

![Structure of post item](https://assets.200lab.io/images/2024/12/05/img-08-structure-post-item-exam-1-a5619d292746b47ca07b.webp)

Phần **Avatar **chúng ta sử dụng **material-ui** nhá, để cài đặt bạn [vào đây](<https://material-ui.com/getting-started/installation>) để copy lệnh cài đặt cũng như đọc docs của nó nếu có hứng thú nhé 😉 copy xong paste vào terminal để cài đặt.

Trong `src`, tạo thêm folder assets để chứa image mà bạn muốn nhé, để có thể sử dụng ta tạo file `ImageList.js`trong `src` rồi copy code như bên dưới, mỗi lần dùng thì chỉ cần `import` vào và dùng thôi nhé 😉.

```
import AVATAR from './assets/avatar/avatar-01.jpg';
export {AVATAR};
```

> **Lưu ý:** Ở đây ta chỉ test khi tạo một **PostItem **thôi, khi có data từ firebase thì ta sẽ sử dụng image từ firebase sau.

Trong `PostItem.jsx` các bạn code như bên dưới.

```js
import React from "react";
import "./Style-PostItem.css";
import { AVATAR, IMG_P_1 } from "../../ImageList";
import Avatar from "@material-ui/core/Avatar";

export default function PostItem() {
  return (
    <div className="post__container">
      {/* Header -> Username + Avatar + Local */}
      <div className="post__header">
        <div className="post__header--block-left">
          <div className="post__header--avatar">
            <Avatar alt="Remy Sharp" src={AVATAR} />
          </div>
        </div>
        <div className="post__header--block-right">
          <div className="post__header--username">
            <a href="/#">d_dev_guys</a>
          </div>
          <div className="post__header--more-option">
            <span>
              <i className="bx bx-dots-horizontal-rounded"></i>
            </span>
          </div>
        </div>
      </div>
      {/* image */}
      <div className="post__image">
        <img src={IMG_P_1} alt="p-1" />
      </div>
      <div className="post__group-bottom">
        {/* Group of interactive icons */}
        <div className="post__group-bottom">
          <div className="icons">
            <div className="icons-left">
              <span>
                <i className="bx bx-heart"></i>
              </span>
              <span>
                <i className="bx bx-message-rounded"></i>
              </span>
              <span>
                <i className="bx bx-paper-plane"></i>
              </span>
            </div>
            <div className="icons-right">
              <span>
                <i className="bx bx-bookmark"></i>
              </span>
            </div>
          </div>
          <div className="post__interactive-info">
            <a href="/#">
              <span>321</span> lượt thích
            </a>
          </div>
        </div>
        {/* Username + Caption */}
        <div className="post__caption">
          <div className="post__caption--user">
            <span className="user-name">
              <a href="/#">d_dev_guys</a>
            </span>
            &nbsp;
            <span className="caption">
              "Don't feel better than anybody, because you feel like something.
              Always have it at the back of your mind that you were nothing
              before you became something, and that thing you supposed to be is
              absolutely nothing."
            </span>
          </div>
          {/* Time */}
          <p className="post__caption--time"><span>1</span> Ngày trước</p>
        </div>
        {/* input field for comment */}
        <div className="post__comment">
            <form>
                <span>
                    <i className='bx bx-smile'></i>
                </span>
                <input type="text" placeholder="Thêm bình luận..." />
                <button className="btn btn-post-comment">Đăng</button>
            </form>
        </div>
      </div>
    </div>
  );
}
```

_PostItem.jsx_

Phần css cho nó, ta làm như bên dưới.

```css
.post__container {
    margin-bottom: 24px;
    border-radius: 3px;
    border: 1px solid #dbdbdb;
    margin-left: -1px;
    margin-right: -1px;
    background-color: #fff;
}

.post__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
    border-bottom: 1px solid #efefef;
}

.post__header--block-right {
    margin-left: 14px;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    flex-grow: 1;
    flex-shrink: 1;
    overflow: hidden;
}

.post__header--username a {
    color: #262626;
    font-weight: 600;
}

.post__header--more-option i.bx-dots-horizontal-rounded {
    font-size: 20px;
    cursor: pointer;
}

.post__image {
    background-color: #efefef;
    display: block;
    width: 100%;
    overflow: hidden;
}

.post__image img {
    height: 100%;
    width: 100%;
    object-fit: cover;
}

.post__group-bottom {
    padding: 0 16px;
    margin-top: 4px;
}

.icons {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.icons .bx {
    font-size: 28px;
    color: #262626;
    padding: 8px;
    cursor: pointer;
}

.icons-left span:first-child {
    margin-left: -8px;
}

.icons-right span {
    transition: all 0.5s ease;
}

.icons-right span:hover {
    opacity: 0.8;
}

.post__interactive-info {
    margin-bottom: 8px;
}

.post__interactive-info a {
    font-weight: 600;
    color: #262626;
    font-size: 14px;
}

.post__caption {
    padding: 0 16px;
}

.user-name a {
    color: #262626;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding-left: 5px;
    margin-left: -5px;
    font-size: 14px;
}

.caption {
    font-size: 14px;
    font-weight: 400;
    color: rgb(85, 85, 85);
}

.post__caption--time {
    font-size: 10px;
    color: #8e8e8e;
    margin-bottom: 5px;
    text-transform: uppercase;
}

.post__comment {
    margin-top: 4px;
    border-top: 1px solid #efefef;
    color: #8e8e8e;
    max-height: 56px;
    padding: 13px 0;
}

.post__comment form {
    display: flex;
    align-items: center;
    justify-content: space-between;

}

.post__comment form input {
    width: 100%;
    height: 18px;
    padding: 9px;
    outline: none;
    border: none;
}

.btn-post-comment {
    background-color: transparent;
    color: #0095f6;
    font-weight: 600;
}
```

_Style-PostItem.css_

Đây là code trong `App.js` hiện tại của mình.

```js
import React from 'react'
import './App.css';
import Header from './components/Header/Header'
import PostItem from './components/PostItem/PostItem'

function App() {
  return <div className="App">
    {/* Header */}
    <Header/>
    {/* Posts */}
    <div className="Post__list">
      <PostItem />
    </div>
  </div>;
}

export default App;
```

_App.js_

Đây là css chung trong `App.css` hiện tại.

```css
body {
    background-color: #fafafa;
}

a {
    text-decoration: none;
}

.Post__list {
    margin-top: 5rem;
    margin-left: 5rem;
    max-width: 614px;
    width: 100%;
    margin-right: 28px;
}
```

_App.css_

Và đây là thành quả nè 😋.

![](https://assets.200lab.io/images/2024/12/05/img-09-post-item-done-9ad7f2ace371f5bfb008.webp)

## III. Tổng kết

Trong phần 2 này, mình đã hướng dẫn các bạn tạo phần header và bài post cho trang của chúng ta. Trong phần tiếp theo, chúng ta sẽ cùng nhau giải quyết chuyện render cả một đống các bài post nhưng thế nào, cách implement Firebase Database, cách truy cập Database, Authentication, và Storage từ Firebase nhé 😉.

Cảm ơn các bạn đã theo dõi, see u 😉!

## Đọc thêm

- [Event Loop là gì? Cơ chế hoạt động của Event Loop trong JavaScript](https://200lab.io/blog/event-loop-la-gi.md): Event Loop là một cơ chế cho phép xử lý các tác vụ bất đồng bộ trong JavaScript, sử dụng một vòng lặp vô tận để kiểm tra, quản lý các tác vụ.
- [So sánh Golang và NodeJS chi tiết](https://200lab.io/blog/so-sanh-golang-vs-nodejs.md): Golang và NodeJS khác nhau như thế nào? Golang và Nodejs từ lâu đã trở thành chủ đề sôi nổi. Nodejs đã chiếm ưu thế trong một khoảng thời gian dài. Golang liệu có đủ sức thuyết phục để chuyển đổi?
- [ReactJS Tutorial for Beginners Phần 2](https://200lab.io/blog/reactjs-tutorial-for-beginners-phan-2.md): Trong bài viết này chúng ta sẽ đi qua năm nội dung đầu tiên của tutorial
- [ReactJS vs React Native - Gà cùng một mẹ liệu có giống nhau?](https://200lab.io/blog/reactjs-vs-react-native.md): Bạn có đang rối giữa ReactJS vs React Native? Nên chọn cái nào thì tốt hơn? Có thể tái sử dụng code của ReactJS cho React Native hay không? Hãy khám phá câu trả lời thông qua bài viết so sánh ReactJS vs React Native này bạn nhé!
- [Netflix Clone với ReactJS, Styled Components và Firebase (Firestore & Auth) - Phần 7](https://200lab.io/blog/netflix-clone-voi-reactjs-styled-components-va-firebase-firestore-auth-phan-7.md): Nối tiếp phần 6 của series, trong phần này, chúng ta sẽ bắt tay vào code Sign Up page,config lại phần router để đáp ứng được vấn đề Authentication kèm theo tạo custom hook để listening for Authentication. Không dài dòng nữa, Chúng ta bắt đầu thôi 😁.
- [Mọi bài viết chủ đề Javascript](https://200lab.io/blog/tags/javascript.md)

Toàn bộ nội dung: https://200lab.io/llms.txt
