---
title: "Netflix Clone với ReactJS, Styled Components và Firebase (Firestore & Auth) - Phần 3"
description: "Tiếp tục công việc đang dang dở ở phần 2, trong phần 3 này chúng ta sẽ làm phần Footer ở Guest Home Page này, kèm theo đó chúng ta sẽ apply các tool như ESLint và Prettier vào project của chúng ta nhé."
canonical: "https://200lab.io/blog/netflix-clone-voi-reactjs-styled-components-va-firebase-firestore-auth-phan-3"
published: "2021-12-02T01:51:00Z"
updated: "2026-08-21T07:17:37Z"
authors: ["TỪ QUỐC HƯNG"]
tags: ["Javascript"]
reading_minutes: 9
access: "public"
---

Tiếp tục công việc đang dang dở ở phần 2, trong phần 3 này chúng ta sẽ làm phần **Footer** ở **Guest Home Page** này, kèm theo đó chúng ta sẽ apply các tool như **ESLint** và **Prettier** vào project của chúng ta nhé.

## I. Apply normalize.css, ESLint và Prettier.

### 1. Apply normalize.css.

Chúng ta đã install `normalize.css` trước đó rồi, nên giờ chúng ta chỉ việc `import` nó vào nữa thôi là được. Chúng ta sẽ `import` nó vào trong file `index.js` như đường dẫn sau:

Trong `src/index.js`: `import 'normalize.css';`

### 2. Apply ESLint và Prettier.

Trước tiên nếu các bạn chưa cài các extension **ESLint** và **Prettier** trên **Visual studio code** của mình thì các bạn cài 2 cái đó trước nhé, mình sẽ để hình bên dưới.

![ESLint extension](https://assets.200lab.io/images/2024/12/05/image-19-1056b5efb7efd56e704e.webp)

![Prettier extension](https://assets.200lab.io/images/2024/12/05/image-20-7391f1d9f6c16fef6cbc.webp)

Tiếp theo là setting cho **workspace** của chúng ta. Mặc định nếu ta không setting ở **workspace** thì VS code sẽ apply setting ở **user** cho chúng ta luôn. Chúng ta sẽ dùng file Json để setting cho nhanh nhé 😉.

Tạo file theo đường dẫn sau ở folder chính: `.vscode/settings.json`

```JSON
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}
```

_settings.json_

**_Note:_**

- `"editor.defaultFormatter"`: Chúng ta sẽ chọn **default formatter** là **Prettier** (bạn có thể sửa lại formatter khác cũng được nhé).
- `"editor.formatOnSave"`: set bằng `true` để khi ta save thì nó sẽ tự động format code của chúng ta theo **Prettier** mà ta đã define ở trên (Nếu không thích thì set thành `false` nhé).
- `"source.fixAll.eslint"`: set bằng `true`, tức là khi save thì **ESLint** sẽ auto format code và fix các lỗi liên quan đến convention luôn cho chúng ta (Nếu không thích thì set thành `false`).

Tiếp theo, các bạn cài cho mình thêm 1 extension nữa như hình bên dưới.

![EditorConfig for VS code extension](https://assets.200lab.io/images/2024/12/05/image-21-bf2057fe86a79a76b409.webp)

Sau đó, ta tạo file `.editorconfig` trong folder chính của project của mình nhé, sau đó thêm đoạn setting bên dưới.

```JSON
[*]
end_of_line = lf
indent_style = tab
indent_size = 4
```

_.editorconfig_

**_Note:_** **EditorConfig** có tác dụng là thống nhất các chuẩn format giữa các editor khác nhau. **EditorConfig** giúp code chúng ta có tính thống nhất, dễ đọc và bảo trì. Khi cài extension trên thì nó sẽ tự apply file `.editorconfig` mà ta đã tạo.

_(Các bạn có thể đọc thêm docs của các extension để hiểu rõ hơn nhé)._

Các bạn cài thêm package này: `npm i prettier eslint-config-prettier eslint-plugin-prettier -D`. Nó có tác dụng tắt các rule không cần thiết hoặc dễ xung đột với **Prettier**.

Trong phần `scripts` của file `package.json` ta thêm đoạn scripts như sau:

```JSON
"lint": "eslint --ext src/**/*.js,*.jsx,*.ts,*.tsx",
"lint:fix": "eslint --fix --ext src/**/*.js,*.jsx,*.ts,*.tsx",
"prettier": "prettier --check \"src/**/(*.tsx|*.ts|*.jsx|*.js|*.scss|*.css)\"",
"prettier:fix": "prettier --write \"src/**/(*.tsx|*.ts|*.jsx|*.js|*.scss|*.css)\""
```

_Script in package.json_

Đoạn script trên dùng cho cả **Typescript** và **Javascript** nên nếu bạn không thích thì có thể bỏ những phần liên quan đến `.ts` hay `.tsx` đi nhé.

Tại sao lại thêm đoạn scripts trên? Okie với đoạn scripts trên ta chỉ cần gõ lệnh `npm run lint` thì **ESLint** sẽ auto scan toàn bộ project của chúng ta để thìm các lỗi, sau đó ta chỉ cần gõ `npm run lint:fix` thì nó sẽ auto fix toàn bộ file nào lỗi mà nó scan được trong project của chúng ta. Tương tự với ông thần **Prettier**.

Tiếp theo tạo thêm file `.prettierrc` ở folder chính của project để set các rules cho thằng **Prettier**

```JSON
{
  "arrowParens": "always",
  "semi": true,
  "trailingComma": "none",
  "endOfLine": "lf",
  "tabWidth": 4,
  "useTabs": true
}
```

_.prettierrc_

Tạo thêm file `.prettierignore` nó tương tự như thằng `.gitignore` nhưng cái này dành cho **Prettier**, để tránh format các file không cần thiết.

```JSON
.cache
package-lock.json
```

_.prettierignore_

Ta tạo thêm file `.eslintrc` để cấu hình thêm cho thằng **ESLint**.

```JSON
{
  "extends": ["react-app", "prettier"],
  "plugins": ["react", "prettier"],
  "rules": {
    "prettier/prettier": [
      "warn",
      {
        "arrowParens": "always",
        "semi": true,
        "trailingComma": "none",a
        "endOfLine": "lf",
        "tabWidth": 4,
        "useTabs": true
      }
    ],
    "no-console": "warn"
  }
}
```

_.eslintrc_

Cuối cùng ta thêm file `.eslintignore` cho **ESlint** biết không cần bắt lỗi với những file được khai báo trong này.

```JSON
/src/serviceWorker.js
/src/setupTests.js.js
```

_.eslintignore_

## II. Implement Footer UI.

Trong folder **src** ta tạo thêm folder **containers** và **pages,** trong folder **containers** tạo thêm file `storyContainer.jsx`, folder **pages** tạo thêm file `home.jsx`. Tiếp theo, trong folder **components** ta thêm file `index.jsx`.

Tại sao ta lại thêm file này? Thì file này nhằm mục đích là sẽ dùng để gọm các component của chúng ta vào 1 nơi để quản lý, khi nào cần sử dụng thì ta sẽ `import` theo dạng **Alias** thì sẽ gọn gàng và dễ quản lý hơn.

- Trong `/components/index.jsx`:

```JS
import Story from "./story/index";

export { Story };
```

_index.jsx_

- Trong `/containers/storyContainer.jsx` ta copy từ `App.js` và edit lại như sau:

```JS
import React from "react";
import { Story } from "../components/index";
import storiesData from "../fixtures/stories.json";

export default function StoryContainer() {
	return (
		<Story.Container>
			{storiesData.map((story) => (
				<Story key={story.id} direction={story.direction}>
					<Story.BlockPane>
						<Story.Title>{story.title}</Story.Title>
						<Story.SubTitle>{story.subTitle}</Story.SubTitle>
					</Story.BlockPane>
					{story.image ? (
						<Story.BlockPane>
							<Story.Image
								src={story.image}
								alt={story.alt}
							></Story.Image>
						</Story.BlockPane>
					) : (
						""
					)}
				</Story>
			))}
		</Story.Container>
	);
}
```

_storyContainer.jsx_

_**Note:** Chú ý kiểu `import` của component **Story** nhé_😉.

- Trong file `App.js` ta edit lại như sau:

```JS
import React from "react";
import StoryContainer from "./containers/storyContainer";

export default function App() {
	return <StoryContainer />;
}
```

_App.js_

Giờ mới thực sự implement phần **Footer** nè hehe 😁, ta tạo component **Footer** như hình:

![Footer folder](https://assets.200lab.io/images/2024/12/05/image-22-53f12652ee3d9a6d6b7b.webp)

- Trong file `footer.jsx`, ta thêm đoạn code sau:

```JS
import styled from "styled-components/macro";

export const Container = styled.div`
	display: flex;
	flex-direction: column;
	margin: auto;
	padding: 70px 45px;
	max-width: 1000px;

	@media screen and (max-width: 1000px) {
		padding: 70px 30px;
	}
`;

export const Wrapper = styled.div`
	display: inline-block;
	position: relative;
	margin-bottom: 1rem;
`;

export const Column = styled.div`
	display: flex;
	flex-direction: column;
	text-align: left;
`;

export const Row = styled.div`
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
	grid-gap: 15px;

	@media screen and (max-width: 1000px) {
		grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
	}
`;

export const Link = styled.a`
	color: #757575;
	margin-bottom: 20px;
	font-size: 13px;
	text-decoration: none;
	&:hover {
		text-decoration: underline;
	}
`;

export const Title = styled.p`
	font-size: 16px;
	color: #757575;
	margin-bottom: 40px;
	cursor: pointer;
	&:hover {
		text-decoration: underline;
	}
`;

export const Text = styled.p`
	font-size: 13px;
	color: #757575;
	margin-bottom: 40px;
`;

export const Break = styled.div`
	flex-basis: 100%;
	height: 0;
`;

export const SelectWrap = styled.div`
	position: relative;
	display: inline-block;
	width: 100%;
	&::before {
		content: "\f0ac";
		font-family: "Font Awesome 5 Free";
		font-weight: 900;
		position: absolute;
		top: 15px;
		left: 15px;
		color: #999;
		font-size: 16px;
		pointer-events: none;
	}
`;

export const Select = styled.select`
	text-indent: 0;
	line-height: 1.7;
	background-color: #000;
	background-image: none;
	border: 1px solid #333;
	color: #999;
	font-size: 16px;
	padding: 12px 26px 12px 45px;
	border-radius: 2px;
`;
export const Option = styled.option``;
```

_footer.jsx_

- Trong `/footer/index.jsx` ta thêm đoạn code như sau:

```JS
import React from "react";
import {
	Column,
	Container,
	Row,
	Link,
	Title,
	Text,
	Break,
	Select,
	Option,
	Wrapper,
	SelectWrap
} from "./styles/footer";

export default function Footer({ children, ...restProps }) {
	return <Container {...restProps}>{children}</Container>;
}

Footer.Wrapper = function FooterWrapper({ children, ...restProps }) {
	return <Wrapper {...restProps}>{children}</Wrapper>;
};

Footer.Row = function FooterRow({ children, ...restProps }) {
	return <Row {...restProps}>{children}</Row>;
};

Footer.Column = function FooterColumn({ children, ...restProps }) {
	return <Column {...restProps}>{children}</Column>;
};

Footer.Link = function FooterLink({ children, ...restProps }) {
	return <Link {...restProps}>{children}</Link>;
};

Footer.Title = function FooterTitle({ children, ...restProps }) {
	return <Title {...restProps}>{children}</Title>;
};

Footer.Text = function FooterText({ children, ...restProps }) {
	return <Text {...restProps}>{children}</Text>;
};

Footer.Break = function FooterBreak({ children, ...restProps }) {
	return <Break {...restProps}>{children}</Break>;
};

Footer.SelectWrap = function FooterSelectWrap({ children, ...restProps }) {
	return <SelectWrap {...restProps}>{children}</SelectWrap>;
};

Footer.Select = function FooterSelect({ children, ...restProps }) {
	return <Select {...restProps}>{children}</Select>;
};

Footer.Option = function FooterOption({ children, ...restProps }) {
	return <Option {...restProps}>{children}</Option>;
};
```

_index.jsx_

Okie! tiếp theo chúng ta sẽ implement **Footer**, trong folder **containers** ta tạo thêm file `footerContainer.jsx`, trong file này chúng ta sẽ code như sau:

```JS
import { React } from "react";
import { Footer } from "../components/index";

export default function FooterContainer() {
	return (
		<Footer>
			<Footer.Title>Questions? Contact us.</Footer.Title>
			<Footer.Break />
			<Footer.Row>
				<Footer.Column>
					<Footer.Link href="#">FAQ</Footer.Link>
					<Footer.Link href="#">Investor Relations</Footer.Link>
					<Footer.Link href="#">Privacy</Footer.Link>
					<Footer.Link href="#">Speed Test</Footer.Link>
				</Footer.Column>
				<Footer.Column>
					<Footer.Link href="#">Help Center</Footer.Link>
					<Footer.Link href="#">Jobs</Footer.Link>
					<Footer.Link href="#">Cookie Preferences</Footer.Link>
					<Footer.Link href="#">Legal Notices</Footer.Link>
				</Footer.Column>
				<Footer.Column>
					<Footer.Link href="#">Account</Footer.Link>
					<Footer.Link href="#">Ways to Watch</Footer.Link>
					<Footer.Link href="#">Corporate Information</Footer.Link>
					<Footer.Link href="#">Only on Netflix</Footer.Link>
				</Footer.Column>
				<Footer.Column>
					<Footer.Link href="#">Media Center</Footer.Link>
					<Footer.Link href="#">Terms of Use</Footer.Link>
					<Footer.Link href="#">Contact Us</Footer.Link>
				</Footer.Column>
			</Footer.Row>
			<Footer.Break />
			<Footer.Wrapper>
				<Footer.SelectWrap>
					<Footer.Select defaultValue="/vn-en/">
						<Footer.Option value="/vn-en/">English</Footer.Option>
						<Footer.Option value="/vn/">Vietnamese</Footer.Option>
					</Footer.Select>
				</Footer.SelectWrap>
			</Footer.Wrapper>
			<Footer.Break />
			<Footer.Text>Netflix Vietnam</Footer.Text>
		</Footer>
	);
}
```

_footerContainer.jsx_

Okie! Đã xong, chúng ta chạy thử xem thế nào nhé.

![Footer UI Demo](https://assets.200lab.io/images/2024/12/05/image-23-83d47607aa8d0c3f4fe9.webp)

Vậy là đã xong phần **Footer** hehe 😁.

## III. Tổng kết.

Okie! bài hôm nay hơi dài, nên mình sẽ tạm kết thúc tại đây, hy vọng bài này sẽ giúp ích cho các bạn thêm về code cũng như làm quen với những tool checking code cũng như convention khi code, giúp chúng ta bớt "gà" hơn, code của chúng ta được gọn gàng và đẹp hơn hehe 😁. Những tool này khi đi làm chắc chắn sẽ có và người ta sẽ bắt rất là kỹ do đó các bạn tập làm quen và tìm hiểu nó nhé 😉. See u again!
