I. React Context for firebase.
Để các component có sử dụng các data do firebase trả về mà không cần truyền data theo kiểu nested từ cha → con, một kiểu truyền thống (phức tạp) thì chúng ta sẽ tạo một context có cho firebase như sau:
- Trong folder src ta tạo folder và file như sau:
/src/context/firebase.js
import { createContext } from "react";
export const FirebaseContext = createContext(null);
firebase.js
- Trong file
/src/index.js
, ta edit lại như sau:
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { GlobalStyles } from "./global-styles";
import { firebase } from "./lib/firebase.prod";
import { FirebaseContext } from "./context/firebase"; //<----- here
ReactDOM.render(
<React.StrictMode>
<FirebaseContext.Provider value={{ firebase }}> {/* <----- here */}
<GlobalStyles />
<App />
</FirebaseContext.Provider>
</React.StrictMode>,
document.getElementById("root")
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: <https://bit.ly/CRA-vitals>
reportWebVitals();
src/index.js
Okie! Cơ bản như vậy đã xong, giờ chúng ta sang bước tiếp theo, tạo Sign In Page nhé 😉.
II. Tạo Sign In page.
Sign In page thì cũng có phần header và footer như bên trang Home thôi.
Trong file /pages/signin.jsx
, ta thêm đoạn code như sau:
import React from "react";
import { HeaderContainer, FooterContainer } from "../containers/index";
export default function SignIn() {
return (
<>
<HeaderContainer>
</HeaderContainer>
<FooterContainer />
</>
);
}
signin.jsx
Ta sẽ được như hình ở dưới đây:
Okie, So sánh phần UI Sign In của Netflix real và Netflix clone của chúng ta hiện tại thì sẽ có 2 thứ phải làm:
- Đầu tiên là phần form Sign In,
- Thứ 2 là phần Select box và button Sign In ở header, chúng ta sẽ ẩn nó đi ở Sign In page này.
Phần form để Sign In và cách để ẩn Select box và button Sign In, ta thực hiện như sau:
- Trong folder components tạo thêm foder và file như sau:
- Trong file
form.jsx
ta code như sau:
import styled from "styled-components/macro";
import { Link } from "react-router-dom";
export const Container = styled.div`
display: flex;
flex-direction: column;
background-color: rgba(0, 0, 0, 0.75);
border-radius: 4px;
box-sizing: border-box;
min-height: 515px;
width: 100%;
margin: auto;
max-width: 450px;
padding: 20px 0 30px;
@media only screen and (min-width: 500px) {
min-width: 380px;
}
@media only screen and (min-width: 740px) {
min-height: 660px;
padding: 60px 68px 40px;
margin-bottom: 90px;
}
`;
export const ErrorMessage = styled.div`
background-color: #e87c03;
border-radius: 4px;
font-size: 14px;
margin: 0 0 14px;
color: #fff;
padding: 15px 20px;
`;
export const Base = styled.form`
display: flex;
flex-direction: column;
width: 100%;
flex-grow: 0.5;
`;
export const Title = styled.h1`
color: #fff;
font-size: 32px;
font-weight: 700;
margin-bottom: 28px;
padding: 0;
`;
export const Text = styled.p`
color: #737373;
font-size: 16px;
font-weight: 500;
`;
export const SmallText = styled.span`
margin-top: 10px;
font-size: 13px;
line-height: normal;
color: #8c8c8c;
`;
export const RedirectLink = styled(Link)`
color: #fff;
text-decoration: none;
&:hover {
text-decoration: underline;
}
`;
export const SmallLink = styled(RedirectLink)`
color: #b3b3b3;
cursor: pointer;
font-size: 13px;
font-weight: 500;
padding-top: 2px;
`;
export const Input = styled.input`
background: #333;
border-radius: 4px;
border: 0;
color: #fff;
height: 50px;
line-height: 50px;
padding: 5px 20px;
width: 100%;
box-shadow: none;
box-sizing: border-box;
font-size: 16px;
display: block;
appearance: none;
margin-bottom: 16px;
`;
export const Button = styled.button`
border: 0;
border-radius: 4px;
font-size: 16px;
font-weight: 700;
margin: 24px 0 12px;
background: #e50914;
position: relative;
box-shadow: 0 1px 0 rgb(0 0 0 / 55%);
color: #fff;
cursor: pointer;
letter-spacing: 0.1px;
user-select: none;
text-align: center;
@media only screen and (min-width: 360px) {
width: 100%;
max-width: 100%;
}
@media only screen and (min-width: 500px) {
padding: 16px;
display: inline-block;
min-width: 98px;
min-height: 37px;
line-height: 1em;
&:disabled {
opacity: 0.8;
}
}
`;
export const CheckBox = styled.input`
width: 16px;
height: 16px;
`;
export const Wrapper = styled.div`
display: flex;
align-items: center;
`;
export const FlexBox = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
`;
export const SocialButton = styled.button`
margin-top: 16px;
min-height: 0;
width: auto;
border: 0;
background: 0 0;
box-shadow: none;
padding: 0;
margin: 0;
`;
export const Image = styled.img`
width: 20px;
height: 20px;
margin-right: 10px;
vertical-align: middle;
`;
form.jsx
- Trong file
/form/index.jsx
, ta code như sau:
- Tiếp đến là file
/pages/signin.jsx
, chúng ta code như sau:
signin.jsx
Giải thích một tý cho code của file ở trên nhé:
State
: Ta có 3 state gồm:email
,password
vàerrorMessage
.isInvalid
: Đơn giản, chỉ check khi user nhập đầy đủ email và password thì mới hiện rõ button Sign In cho người dùng nhấn.handleSignIn()
: Function handle việc Sign In, nó sẽ send request lên firebase gồmemail
vàpassword
để Sign In. Nếu thành công thì sẽ redirect đến Browse page, ngược lại sẽ show message error lên view.status="signin"
: Ở phầnHeaderContainer
, mình có truyền prop làstatus
vào header để check khi redirect sang Sign In page rồi thì ẩn phần select box và button Sign In đi.
Trong file headerContainer.jsx
ta edit lại như sau:
import React from "react";
import { Header } from "../components/index";
import * as ROUTES from "../constants/routes";
export default function HeaderContainer({ children, status }) {
return (
<Header>
<Header.Frame>
<Header.Wrapper>
<Header.Logo
to={ROUTES.HOME}
alt="Netflix-clone"
src="/images/logo.svg"
/>
{/* Handle hidden or show is here */}
{status === "signin" ? (
""
) : (
<Header.WrapBlock>
<Header.WrapSelect>
<Header.Select>
<Header.Option value="/vn-en/">
English
</Header.Option>
<Header.Option value="/vn/">
Vietnamese
</Header.Option>
</Header.Select>
</Header.WrapSelect>
<Header.ButtonLink to={ROUTES.SIGN_IN}>
Sign In
</Header.ButtonLink>
</Header.WrapBlock>
)}
</Header.Wrapper>
</Header.Frame>
{children}
</Header>
);
}
headerContainer.jsx
Okie! Sau khi xong, chúng ta sẽ được UI như hình:
Để có thể sử dụng được chức năng Sign In bằng email và password thì ta phải đăng ký với firebase trước, để đăng ký các bạn làm như sau:
- Step 1.
- Step 2.
Kết quả được như hình là đã thành công rồi.
Vì ban đầu chưa có Sign Up page để ta đăng ký account do đó ta chưa có thể Sign In lúc này. Tuy nhiên, để test thử việc Sign In bằng email và password với firebase có được hay không, chúng ta sẽ add trực tiếp 1 user vào Authentication của firebase như sau:
Step 1.
Step 2: Thêm email và password (Tùy ý các bạn).
Kết quả sẽ được như hình.
Chúng ta sẽ test thử 2 trường hợp là nhập đúng email, password và sai email hoặc password nhé.
Nhập đúng email và password:
Nhập sai email.
III. Tổng kết.
Okie! Như vậy là đã xong phần thứ 6 của series này. Trong phần này, mình đã hướng dẫn các bạn setup React Context cho firebase, phân thích cũng như code nên Sign In page hoàn chỉnh, giống 99.99% so với hàng real 😁, setup authentication cho project của chúng ta và test chức năng Sign In. Trong phần tiếp theo, chúng ta sẽ làm Sign Up page, config lại phần router để đáp ứng được vấn đề Authentication và nhiều thứ khác. Cảm ơn các bạn đã đọc 😊, See u again~