, January 27, 2022

0 kết quả được tìm thấy

Netflix Clone với ReactJS, Styled Components và Firebase (Firestore & Auth) - Phần 3


  •   8 min reads
Netflix Clone với ReactJS, Styled Components và Firebase (Firestore & Auth) - Phần 3

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 FooterGuest Home Page này, kèm theo đó chúng ta sẽ apply các tool như ESLintPrettier 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 ESLintPrettier 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
Prettier extension

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

{
  "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 formatterPrettier (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

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.

[*]
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:

"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ả TypescriptJavascript 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

{
  "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.

.cache
package-lock.json
.prettierignore

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

{
  "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.

/src/serviceWorker.js
/src/setupTests.js.js
.eslintignore

Trong folder src ta tạo thêm folder containerspages, 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:
import Story from "./story/index";

export { Story };
index.jsx
  • Trong /containers/storyContainer.jsx ta copy từ App.js và edit lại như sau:
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:
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
  • Trong file footer.jsx, ta thêm đoạn code sau:
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:
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:

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

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!

Bài viết cùng seri

Bài viết liên quan

ReactJS Tutorial for Beginners Phần 2

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 Tutorial for Beginners Phần 2
ReactJS vs React Native - Gà cùng một mẹ liệu có giống nhau?

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é!...

ReactJS vs React Native - Gà cùng một mẹ liệu có giống nhau?
Netflix Clone với ReactJS, Styled Components và Firebase (Firestore & Auth) - Phần 7

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 😁....

Netflix Clone với ReactJS, Styled Components và Firebase (Firestore & Auth) - Phần 7
Netflix Clone với ReactJS, Styled Components và Firebase (Firestore & Auth) - Phần 6

Trong phần này, chúng ta sẽ config React Context firebase cho project của chúng ta, sau đó tạo Sign In Page và apply Authentication màfirebase cung cấp cho project của chúng ta nhé. Bắt đầu thôi 😉!...

Netflix Clone với ReactJS, Styled Components và Firebase (Firestore & Auth) - Phần 6
Netflix Clone với ReactJS, Styled Components và Firebase (Firestore & Auth) - Phần 5

Trong phần 5 này, chúng ta sẽ hoàn thiện Guest Home Page và config để connect với firebase, chuẩn bị cho các phần tiếp theo nhé 😉....

Netflix Clone với ReactJS, Styled Components và Firebase (Firestore & Auth) - Phần 5
You've successfully subscribed to 200Lab Blog
Great! Next, complete checkout for full access to 200Lab Blog
Xin chào mừng bạn đã quay trở lại
OK! Tài khoản của bạn đã kích hoạt thành công.
Success! Your billing info is updated.
Billing info update failed.
Your link has expired.