Cổng thông tin học sinh

Kho tàng kiến thức và tài nguyên học tập hữu ích

Hướng dẫn clone instagram với React JS và Firebase phần 4.

07 May, 2025 Javascript #clone-instagram • Chill mỗi ngày
Hướng dẫn clone instagram với React JS và Firebase phần 4.

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 😉

Mục lục

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

Authentication in Navbar
Authentication in Navbar

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

Sign-in method
Sign-in method

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

Sign-in providers - Email/Password
Sign-in providers - Email/Password

Chọn nó và tick vào để Enable nó lên và nhấn Save.

Enable method
Enable method

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.

JS
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:

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

Sign up form
Sign up form

Đâ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:

JS
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:

JS
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) => {
		setOpenModal(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={openModal} onClose={() => setOpenModal(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;
'>Copy
        
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);
	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();
	}, []);

	useEffect(() => {
		const unSubcribe = auth.onAuthStateChanged((authUser) => {
			if(authUser) {
				// user has logged in...
				setUser(authUser);
                setUsername(authUser.displayName);
			} 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) => {
		setOpenModal(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 sign up */}
			<Modal open={openModal} onClose={() => setOpenModal(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;
⬅ Về trang chủ