Hello các bạn, trong phần 4 này chúng ta sẽ cùng nhau tìm hiểu và sử dụng các phương thức mà firebase cung cấp cho chúng ta để có thể đăng ký một tài khoản, sử dụng nó để Sign In vào app của mình 😁 nào chúng ta bắt đầu thôi 😉
I. Setup authentication với Firebase.
User authentication hay xác thực người dùng, đây là quá trình định danh (hay xác định) một tài khoản đang login vào hệ thống nó có phải thuộc hệ thống đó hay không. Đây là bước khá quan trọng trong một hệ thống mà có yếu tố người dùng.
Bình thường chúng ta chỉ có thể xem các bài post có sẵn của những user khác mà thôi, chúng ta không thể thao tác nào khác với các bài post đó. Lúc này chúng ta cần phải tạo một tài khoản, sau đó sử dụng nó để Sign In vào app của chúng ta, khi đó chúng ta có thể tạo mới hoặc tương tác với các bài post đó.
Đầu tiên để setup authentication, ta cần mở thanh navigation ra và chọn Authentication
Sau đó bạn sẽ thấy giao diện như hình và nhấn vào button Set up sign-in method hoặc nhấn vào tab Sign-in method như hình nhé. Nếu nó hiện ra cho bạn một background màu hồng "nam tính" thì bạn sẽ thấy button Get started ở đó, hãy nhấn vào nhé 😁 thì nó sẽ hiện ra phần Sign-in method luôn cho bạn 😉.
Sau khi chọn như mình hướng dẫn thì ta sẽ thấy toàn bộ những cách thứ mà firebase cung cấp cho chúng ta để có thể Authentication. Ở phần này mình sẽ sử dụng phương thức Authentication bằng Email/Password nha, các bạn có thể sử dụng những cái khác cũng được cũng không sao cả nếu bạn biết nhé 😉.
Chọn nó và tick vào để Enable nó lên và nhấn Save.
II. Tạo form SignIn và SignUp với Material-UI
Chúng ta sẽ sử dụng phần modal được tạo sẵn từ Material UI nhé, bạn có thể tham khảo code của mình ở bên dưới. Đây là file App.js
, mình có copy một số code của phần modal mà Material UI cung cấp.
import React, { useState, useEffect } from "react";
import "./App.css";
import Header from "./components/Header/Header";
import PostItem from "./components/PostItem/PostItem";
import { db } from "./firebaseConfig";
import { collection, getDocs } from "firebase/firestore";
import { makeStyles } from "@material-ui/core/styles";
import Modal from "@material-ui/core/Modal";
function getModalStyle() {
const top = 50;
const left = 50;
return {
top: `${top}%`,
left: `${left}%`,
transform: `translate(-${top}%, -${left}%)`,
};
}
const useStyles = makeStyles((theme) => ({
paper: {
position: "absolute",
width: 400,
backgroundColor: theme.palette.background.paper,
border: "2px solid #000",
boxShadow: theme.shadows[5],
padding: theme.spacing(2, 4, 3),
},
}));
function App() {
const [posts, setPosts] = useState([]);
const [open, setOpen] = useState(false); // Check open modal
const classes = useStyles();
const [modalStyle] = React.useState(getModalStyle);
//useEffect -> Runs a piece of code based on a specific condition.
useEffect(() => {
// this is where the code runs
getData();
}, []);
const getData = async () => {
const postsCol = collection(db, "posts");
const snapshot = await getDocs(postsCol);
setPosts(
snapshot.docs.map((doc) => ({
id: doc.id,
post: doc.data(),
}))
);
};
const handleClickSignUp = (childData) => {
setOpen(childData);
}
return (
<div className="App">
{/* Header */}
<Header takeMessSignUp={handleClickSignUp} />
{/* Posts */}
<div className="Post__list">
{posts.map(({ id, post }) => (
<PostItem key={id} data={post} />
))}
</div>
<Modal open={open} onClose={() => setOpen(false)}>
<div style={modalStyle} className={classes.paper}>
<h2 id="simple-modal-title">Text in a modal</h2>
</div>
</Modal>
</div>
);
}
export default App;
Giải thích tý nè 😁
getModalStyle()
: Function này để ta style cho modal phần vị trí hiển thi nó trên màn hình.useStyles
: Chứa đống style css cho modal của chúng ta.handleClickSignUp(childData)
: Là một callback function để ta có thể hứng dữ liệu được truyền từ child component là Header ra parent component là App cho chúng ta biết là lúc nào có thể show modal.takeMessSignUp={handleClickSignUp}
: Truyền callback vào để hứng data từ component con thông qua attribute làtakeMessSignUp
Trong Header component ta có code như sau:
import React, { useState } from "react";
import Button from "@material-ui/core/Button";
import "./Style-Header.css";
export default function Header(props) {
const [openModal, setOpenModal] = useState(true);
const transferMesageSignUp = () => {
setOpenModal(true);
props.takeMessSignUp(openModal);
};
return (
<div className="container">
<div className="header">
<div className="header__logo">
<a href="/#">
<img
src="https://www.instagram.com/static/images/web/mobile_nav_type_logo.png/735145cfe0a4.png"
alt="Logo"
/>
</a>
</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
onClick={transferMesageSignUp}
className="btn btn-login"
>
Sign up
</Button>
</div>
</div>
</div>
);
}
Sau khi add được modal có sẵn từ Material-ui ta có thể custom nó thành form Sign Up và Sign In, tất nhiên bạn có thể tùy ý custom theo ý muốn cũng được nhé 😁.
Đầu tiên ta cần tạo form Sign Up và handle form này để ta có thể đăng ký tài khoản cho app của chúng ta.
Đây là UI của form SignUp, bước tiếp theo ta sử dụng những method mà firebase cung cấp cho chúng ta để tiến hành xử lý việc đăng ký tài khoản thôi 😁.
Trong file firebaseConfig.js
ta chỉnh sửa lại một chút như sau:
import firebase from 'firebase/compat';
const firebaseApp = firebase.initializeApp( {
apiKey: "***************************************",
authDomain: "***************************************",
databaseURL: "***************************************",
projectId: "***************************************",
storageBucket: "***************************************",
messagingSenderId: "************",
appId: "***************************************",
measurementId: "************"
});
const db = firebaseApp.firestore();
const auth = firebaseApp.auth();
const storage = firebaseApp.storage();
export { db, auth, storage };
Việc config lại như trên, giúp ta có thể sử dụng các style code với firebase version trước phiên bản 9.0 ngay trên bản mới này luôn. Nên các bạn chú ý chút về điều này nhé 😁.
Trong file App.js
các bạn thêm đoạn code sau:
import { auth, db } from "./firebaseConfig";
//...
import { Button, Input } from '@material-ui/core';
//...
function App() {
//...
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [username, setUsername] = useState('');
const [user, setUser] = useState(null);
//...
//useEffect -> Runs a piece of code based on a specific condition.
useEffect(() => {
// this is where the code runs
getData();
}, []);
useEffect(() => {
const unSubcribe = auth.onAuthStateChanged((authUser) => {
if(authUser) {
// user has logged in...
setUser(authUser);
setUsername(authUser.displayName);
if(authUser.displayName) {
//don't update username
} else {
// if we just create someone...
return updateProfile(authUser, {
displayName: username,
});
}
} else {
// user has logged out...
setUser(null);
}
});
return () => {
// Perform some cleanup actions
unSubcribe();
}
}, [user, username])
const getData = async () => {
const postsCol = collection(db, "posts");
const snapshot = await getDocs(postsCol);
setPosts(
snapshot.docs.map((doc) => ({
id: doc.id,
post: doc.data(),
}))
);
};
const handleClickSignUp = (childData) => {
setOpen(childData);
}
const handleSignUp = (event) => {
event.preventDefault();
auth.createUserWithEmailAndPassword(email, password).then((authUser) => {
return authUser.user.updateProfile({
displayName: username
});
}).catch((error) => alert(error.message));
setOpenModal(false);
}
return (
<div className="App">
{/* Header */}
<Header takeMessSignUp={handleClickSignUp} />
{/* Posts */}
<div className="Post__list">
{posts.map(({ id, post }) => (
<PostItem key={id} data={post} />
))}
</div>
//Modal form sign up
<Modal open={open} onClose={() => setOpen(false)}>
<div style={modalStyle} className={classes.paper}>
<form className="form__signup">
<img className="form__logo"
src="https://www.instagram.com/static/images/web/mobile_nav_type_logo.png/735145cfe0a4.png"
alt="Logo"
/>
<div className="form__group">
<label>User name:</label>
<Input className="form__field" placeholder="username" type="text" value={username} onChange={(e) => setUsername(e.target.value)} />
</div>
<div className="form__group">
<label>Email:</label>
<Input className="form__field" placeholder="email" type="text" value={email} onChange={(e) => setEmail(e.target.value)} />
</div>
<div className="form__group">
<label>Password:</label>
<Input className="form__field" placeholder="password" type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
</div>
<Button className="btn-signup" onClick={handleSignUp}>Sign up</Button>
</form>
</div>
</Modal>
</div>
);
}
export default App;
function handleSignUp()
dùng để bắt sự kiện khi ta nhấn button Sign Up trong form Sign up thì gọi function createUserWithEmailAndPassword
firebase sẽ lưu lại những thông tin đó vào trong database sau đó ta có thể sử dụng tài khoản đó để Sign In thôi 😁.
Khi Sign In xong thì mình update displayName
để ta có thể hiển thị khi ta comment dạo để chủ bài post biết 😁. Một cái hay của firebase là khi ta Sign Up thành công nó sẽ tự động Sign In luôn cho ta, để có thể Log Out thì trong file App.js
ta thêm đoạn code như sau:
const handleClickLogOut = (childData) => {
if(childData === true) {
auth.signOut();
}
}
{/* Header */}
<Header takeMessSignUp={handleClickSignUp} takeMessLogOut={handleClickLogOut} user={user}/>
user={user}
: truyền data user cho component header để check khi nào SignUp hoặc Sign In thành công, từ đó ta có thể thay đổi button Sign Up, Sign In và Log Out.takeMessLogOut={handleClickLogOut}
: Truyền callback vào để lấy data mà header truyền ra cho app biết khi nào ta nhấn vào button Log Out để ta thực hiện đăng xuất khỏi app.handleClickLogOut()
: Nhiệm vụ của nó là check xem data từ header truyền ra nếu làtrue
thì thực hiện Log Out khỏi app.
Đây là khi chưa có Sign Up hay Sign In:
Khi đã Sign In hoặc Sign Up thành công:
Ok, giời ta đã có thể đăng ký tài khoản được rồi 😉. Tiếp theo ta dùng tài khoản đã đăng ký và sign in vào app, để Sign In được ta tạo thêm một modal để nhập email và password vào.
Form Sign In chúng ta không cần field User name, do đó chúng ta chỉ việc copy cái modal của phần Sign Up và bỏ field User name đi là được 😁.
Modal Sign In:
<Modal open={openSignInModal} onClose={() => setOpenSignInModal(false)}>
<div style={modalStyle} className={classes.paper}>
<form className="form__signup">
<img className="form__logo"
src="https://www.instagram.com/static/images/web/mobile_nav_type_logo.png/735145cfe0a4.png"
alt="Logo"
/>
<div className="form__group">
<label>Email:</label>
<Input className="form__field" placeholder="email" type="text" value={email} onChange={(e) => setEmail(e.target.value)} />
</div>
<div className="form__group">
<label>Password:</label>
<Input className="form__field" placeholder="password" type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
</div>
<Button className="btn-signup" onClick={handleSignIn}>Sign In</Button>
</form>
</div>
</Modal>
Tiếp theo chúng ta handle việc Sign In, các bạn thêm đoạn code này vào trong App.js
của mình:
//State
const [openSignInModal, setOpenSignInModal] = useState(false)
/* Header: takeMessLogIn={handleClickSignIn} */
<Header takeMessSignUp={handleClickSignUp} takeMessLogOut={handleClickLogOut} takeMessLogIn={handleClickSignIn} user={user}/>
const handleClickSignIn = (childData) => {
setOpenSignInModal(childData);
}
const handleSignIn = (event) => {
event.preventDefault();
auth.signInWithEmailAndPassword(email, password).then(authUser => {
return setUsername(authUser.user.displayName);
}).catch((error) =>
alert(error.message)
);
}
signInWithEmailAndPassword()
: là phương thức mà firebase hổ trợ cho chúng ta có thể Sign In bằng email và password mà ta đã đăng ký.
Và đây là thành quả 😁.
Toàn bộ code trong file App.js
:
Toàn bộ code trong file Header.jsx
:
III. Tổng kết.
Ok, bài viết đến đây mình nghĩ là đã đủ. Chúng ta đã hoàn thành xong việc tạo form Sign Up, Sign In, sử dụng được các phương thức mà firebase cung cấp cho việc authentication và nhúng nó vào trong app của mình. Phần tiếp theo chúng ta sẽ tiến hành lưu những bài post mới kèm theo ảnh vào database nhé 😉. Hẹn gặp các bạn trong phần tiếp theo 😁. Cảm ơn các bạn đã đọc 🤗
TỪ QUỐC HƯNG
Đam mêm lập trình Frontend, Yêu thích việc setup workspace theo phong cách tối giản
follow me :
Bài viết liên quan
NodeJS là gì? Tại sao NodeJS lại phổ biến
Jul 09, 2024 • 8 min read
Event Loop là gì? Cơ chế hoạt động của Event Loop trong JavaScript
Jun 18, 2024 • 7 min read
So sánh Golang và NodeJS chi tiết
Oct 14, 2023 • 22 min read
Home Feed UI Instagram with TailwindCSS: Giới thiệu về series
Nov 28, 2022 • 2 min read
ReactJS Tutorial for Beginners Phần 2
Dec 12, 2021 • 3 min read
ReactJS vs React Native - Gà cùng một mẹ liệu có giống nhau?
Dec 12, 2021 • 14 min read