Blog app with Nextjs (app router), React, MUI framework
19 tháng 7, 2024
Loading...
Loading...
Setting up Firebase Firestore
First, ensure you have set up Firebase in your Next.js project. Install the necessary dependencies:
npm install firebase
npm install @mui/material @emotion/react @emotion/styledCreate a firebase.js file to initialize Firebase:
// firebase.js
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_AUTH_DOMAIN",
projectId: "YOUR_PROJECT_ID",
storageBucket: "YOUR_STORAGE_BUCKET",
messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
appId: "YOUR_APP_ID",
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
export { db };
Creating the Blog Component
Create a Blog component to display individual blog posts:
// components/Blog.js
import React from "react";
import { Card, CardContent, Typography, Chip } from "@mui/material";
const Blog = ({ blog }) => {
return (
<Card>
<CardContent>
<Typography variant="h5" component="div">
{blog.title}
</Typography>
<Typography variant="body2" color="text.secondary">
{blog.content}
</Typography>
<div>
{blog.tags.map((tag) => (
<Chip key={tag} label={tag} />
))}
</div>
</CardContent>
</Card>
);
};
export default Blog;Fetching Blogs with Pagination and Filtering
Create a utility function to fetch blogs from Firestore:
// utils/fetchBlogs.js
import { collection, query, where, orderBy, limit, startAfter, getDocs } from "firebase/firestore";
import { db } from "../firebase";
export const fetchBlogs = async (lastVisible = null, tag = null, pageSize = 5) => {
let q = collection(db, "blogs");
if (tag) {
q = query(q, where("tags", "array-contains", tag));
}
q = query(q, orderBy("createdAt"), limit(pageSize));
if (lastVisible) {
q = query(q, startAfter(lastVisible));
}
const snapshot = await getDocs(q);
const blogs = snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() }));
const lastVisibleDoc = snapshot.docs[snapshot.docs.length - 1];
return { blogs, lastVisible: lastVisibleDoc };
};Creating the Main Blog Page
Create the main blog page to display the list of blogs with pagination and tag filtering:
// pages/blogs/index.js
import React, { useState, useEffect } from "react";
import { fetchBlogs } from "../../utils/fetchBlogs";
import Blog from "../../components/Blog";
import { Button, Container, Grid, TextField, Typography } from "@mui/material";
const BlogsPage = () => {
const [blogs, setBlogs] = useState([]);
const [lastVisible, setLastVisible] = useState(null);
const [tag, setTag] = useState("");
const [loading, setLoading] = useState(false);
useEffect(() => {
const loadBlogs = async () => {
setLoading(true);
const { blogs, lastVisible } = await fetchBlogs();
setBlogs(blogs);
setLastVisible(lastVisible);
setLoading(false);
};
loadBlogs();
}, []);
const loadMoreBlogs = async () => {
setLoading(true);
const { blogs: newBlogs, lastVisible: newLastVisible } = await fetchBlogs(lastVisible, tag);
setBlogs([...blogs, ...newBlogs]);
setLastVisible(newLastVisible);
setLoading(false);
};
const handleFilterChange = (e) => {
setTag(e.target.value);
};
const handleFilterApply = async () => {
setLoading(true);
const { blogs, lastVisible } = await fetchBlogs(null, tag);
setBlogs(blogs);
setLastVisible(lastVisible);
setLoading(false);
};
return (
<Container>
<Typography variant="h4" gutterBottom>
Blogs
</Typography>
<TextField
label="Filter by tag"
variant="outlined"
value={tag}
onChange={handleFilterChange}
fullWidth
margin="normal"
/>
<Button variant="contained" color="primary" onClick={handleFilterApply} disabled={loading}>
Apply Filter
</Button>
<Grid container spacing={2}>
{blogs.map((blog) => (
<Grid item xs={12} sm={6} md={4} key={blog.id}>
<Blog blog={blog} />
</Grid>
))}
</Grid>
{lastVisible && (
<Button variant="contained" color="secondary" onClick={loadMoreBlogs} disabled={loading}>
Load More
</Button>
)}
</Container>
);
};
export default BlogsPage;Adding Firestore Data Security Rules
Ensure you have appropriate security rules in Firestore to allow read access:
service cloud.firestore {
match /databases/{database}/documents {
match /blogs/{blog} {
allow read: if true;
}
}
}Conclusion
This code provides a basic implementation of a blog app with Next.js, Firebase Firestore, and Material-UI. The main features include fetching blogs, filtering by tags, and supporting pagination. Make sure to adjust the Firebase configuration and security rules according to your project’s needs.
✔ Giải mã 100 Đặc điểm của Người Thành công: Bản đồ phát triển bản thân hiệu quả
✔ Bí Kíp Kiếm Tiền Trên Facebook 2025: Hướng Dẫn Toàn Tập Tối Ưu Hóa Thu Nhập
✔ Gemini Miễn phí vs Gemini Pro (Google AI Pro): So sánh tính năng, phí và cách chọn 2025
✔ Veo 3 AI: Hướng dẫn Prompt & Chiến lược GV‑SEO 2025 cho Người Mới và Doanh Nghiệp-Phần 2
✔ Cẩm Nang Veo 3 AI 2025: Hướng Dẫn Viết Prompt Video AI Cho Marketer & Nhà Sáng Tạo
✔ Hành Trình Tự Do Tài Chính: Bí Quyết Tập Trung, Duy Trì Động Lực Và Làm Việc Hiệu Quả
✔ Các Cấp Độ Tiếng Anh và Quy Đổi Điểm TOEIC Chuẩn Xác Nhất 2025
✔ So sánh chi tiết Gemini 2.5 Pro và Gemini Flash 2.5: Hiệu năng, tính năng và ứng dụng thực tế
✔ So sánh Veo 2 và Veo 3: Hướng dẫn tạo prompt, khác biệt chi tiết và ví dụ thực tế