- lets start Our Journey with Next.js
- Clear concept of pre-rendering and client-side-render
- crate Next js app foler stractur
- next js with file system route and dynamic route
- Catch all route
- custom 404 file not found
- second most popular ant design setup
- Automatic home when 404 page
- Using head component , Image component , Import alias , and Moudle Summary
- Getting Started and install some packages
- Folder structure
- run json server
- Data fatching with getStaticProps
- Responsive design for antDesign card
- Note and issus in getStaticProps
- why we save image in public folder in next.js
- when we use static side generated and server side rendering
- Technical Breakdown of Clients side data faching usin RTK Query
- Dynamic import ( lazy loading) No SSR
- Install mongodb create database insert json data into mongodb database and connect to mongodb
- Get and post data into mongodb
- Css Module support in next js
This is a Next.js project bootstrapped with create-next-app
.
- Getting Started nextAuth
- Implement Github authentication with Next Auth
- User in Sessions
- Sign out
- Redirect after login
- show user in profile
- implement email and passoword authenticaion
এখানে আমাদের জানতে হবে । next js কি ? কেন ব্যবহার করতে হয় ।
Next js হচ্ছে react এর framework . React with supper power . যা React এর সাথে combine করে হয়েছে ।
- Built In Optimization
- React এ Image , Font , icon এর ফলে react এর পারফরমেন্স হবি হয়ে যেতো ।
- Next js এ built in optimization থাকার কারণে সে নিজে থেকে এগুলো optimize করে নে ।
- যার কারণে ফাস্ট হয় ।
- Pre-render(SSG + SSR)
- Next js তার performance কে optimize করতে SSG + SSR কনসেপ্ট ব্যবহার করেচে ।
- এজন্য ফাস্ট হয় ।
- Next level Data Fetching
- রিয়েক্ট client side ডাটা fatching করে ।
- নেকস্ট জেস server side data fatiching ডাটা নিয়ে আসে ্
- Powerful Routing and Layouts
- আমরা react এ routing টা dependency আকারে install করেত হয় ।
- Next js এটা অটোমেটিক করে দে ,
- আরো আছে nested route . যা আমরা পরে দেখব ।
- API Routes
- আমরা React এ সাভারেব জন্য express , node ব্যবহারে করে র্সাভার করতে হতো ।
- next এ এগোলো সব দিয়ে দেয়া আছে ।
আর next documantaion এ বলছে full stack করতে চাইলৈ next js ইউজ করতে । আর library হচ্চে ছোটা তিনিস framework হচ্ছে বড় তিনিস ।
আমরা রিযেক্টে fulll stack project করতে thired party লাইব্রেরি ইউজ করতে হতৌ । যেমণ : firebase , react router , express
- next js preRenderg
- Static side Generation (SSG)
- Server side Rendering (SSR)
- react js Client side Rendering
React এ client side rending
Next jas re-rnder এ server side rendering and
pre reander এবু কি যেমন : next এর default url বা শরুর website, right click করে view souce book গেলে বুজা যায় ।
এবার জানতে হবে = Static side Generation টা কেন কলা হয় ।
Clone This Starter File
Then, run
npm install
#or
npm i
npm i json server
npm install @reduxjs/toolkit react-redux
After that, run the development server:
```bash
npm run dev
npx create-next app@latest
এখানে এই কমান্ড দেয়ার পর প্রজেক্ট নেম জিঙ্গেস করবে , eslint , tailwind ব্যবহার করবে কিনা জিঙ্গেস করবে ।
cd my-app
npm run dev
npm install antd -save
then no
yes
no
yes
no
then cd my-add
then npm run dev
pages ফোল্ডারে _app.js and index.js টা অবশ্যই লাগবে ।
docuent.js টা ডিলিট করে দিলাম ।
এবার একটা file create করতে হবে ।
about.js
import React from 'react'
export default function () {
return (
<div>this is about page</div>
)
}
এবার যদি আমরা hit করি
আগে আমরা রিযেক্টে , এভাবে লিখতাম , এখন next js জাস্ট ফাইলের নাম ধরে ডাক দিলাম
const route = [
{
path : "/home",
component : home
}
]
একটা folder create করতে হবে । তারপর একটা file ক্রিয়েট করা ।
- article
- news.js
import React, { Component } from 'react'
export class newws extends Component {
render() {
return (
<div>this is news </div>
)
}
}
export default newws
তাহলে রাউট হবে http://localhost:3000/article/news
জাস্ট ariticle folder e গিয়ে index.js নামে file create করতে হবে ।
import React from 'react';
const index = () => {
return (
<div>
this is home page
</div>
);
};
export default index;
তাহলে url হবে । http://localhost:3000/article/
- article
- post
- post.js
- post
import React from 'react';
const post = () => {
return (
<div>
this is post inside article folder and inside post folder
</div>
);
};
export default post;
তাহলে url হবে । http://localhost:3000/article/post/post আবার আমরা post folder এর মথ্যে home route করতে পারি ।
ui তে যদি দেখাতে চাই তাহলে router.query.productId দিতে হবে । এখানে query দিলাম , কারণ এট url থেকে নিতে হবে । productId দিলাম কেন ? কারণ এটা file name .
import { useRouter } from 'next/router';
import React from 'react';
const productDetails = () => {
const router = useRouter()
return (
<div>
this is dynamic page of product {router.query.productId}
</div>
);
};
export default productDetails;
http://localhost:3000/news/3-04-20023/manday/abc
http://localhost:3000/news/2-3-2023/java/jjsj
এই url এ dynamic date এর পরে আরও route থাকতে পারে । এই dynamic date এর পরে data search করা যেতে পারে ।
for example
- news
- [...slug].js
import React from 'react';
const FilterIng = () => {
return (
<div>
this the filter ing
</div>
);
};
export default FilterIng;
এতন্য file name দিতে হবে
- page
- 404.js
npm install antd --save
import { Button } from 'antd';
import Link from 'next/link';
import React from 'react';
const home = () => {
return (
<Button type="primary">
<Link href = "/"> Home</Link>
</Button>
);
};
export default home;
import { useRouter } from 'next/router';
import React from 'react';
const eror = () => {
const router = useRouter();
setTimeout(() => {
router.push("/")
}, 2000);
return (
<div>
<img src='https://www.nicepng.com/png/detail/373-3734776_404-banner-http-404.png' width="100%"></img>
</div>
);
};
export default eror;
- src
- components
- RootLayout
import React from 'react';
import { Breadcrumb, Layout, Menu, theme } from 'antd';
const { Header, Content, Footer } = Layout;
const RootLayout = ({children}) => {
const {
token: { colorBgContainer },
} = theme.useToken();
return (
<Layout className="layout">
<Header
style={{
display: 'flex',
alignItems: 'center',
}}
>
<div className="demo-logo" />
<Menu
theme="dark"
mode="horizontal"
defaultSelectedKeys={['2']}
items={new Array(15).fill(null).map((_, index) => {
const key = index + 1;
return {
key,
label: `nav ${key}`,
};
})}
/>
</Header>
<Content
style={{
padding: '0 50px',
}}
>
<Breadcrumb
style={{
margin: '16px 0',
}}
>
<Breadcrumb.Item>Home</Breadcrumb.Item>
<Breadcrumb.Item>List</Breadcrumb.Item>
<Breadcrumb.Item>App</Breadcrumb.Item>
</Breadcrumb>
<div
className="site-layout-content"
style={{
background: colorBgContainer,
height: '100vh'
}}
>
{children}
</div>
</Content>
<Footer
style={{
textAlign: 'center',
}}
>
Ant Design ©2023 Created by Ant UED
</Footer>
</Layout>
);
};
export default RootLayout;
_app.js
এখানে আমাদের app getLayout
যদি থাকে বসাই দিবে । নিচে কল করা হয়েছে ।
import '@/styles/globals.css'
export default function MyApp({ Component, pageProps }) {
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout || ((page) => page)
return getLayout(<Component {...pageProps} />)
}
**এখানে আমরা getLayout
property
কে এবং funcion কে assign
করে দিচ্ছি , যার নাম হচ্ছে getLayout
ফাংশন ।
Home.getLayout = function getLayout(page) {
return (
<RootLayout>
{page}
</RootLayout>
)
}
import React, { useState } from 'react';
import {
DesktopOutlined,
FileOutlined,
PieChartOutlined,
TeamOutlined,
UserOutlined,
} from '@ant-design/icons';
import { Breadcrumb, Layout, Menu, theme } from 'antd';
const { Header, Content, Footer, Sider } = Layout;
function getItem(label, key, icon, children) {
return {
key,
icon,
children,
label,
};
}
const items = [
getItem('Option 1', '1', <PieChartOutlined />),
getItem('Option 2', '2', <DesktopOutlined />),
getItem('User', 'sub1', <UserOutlined />, [
getItem('Tom', '3'),
getItem('Bill', '4'),
getItem('Alex', '5'),
]),
getItem('Team', 'sub2', <TeamOutlined />, [getItem('Team 1', '6'), getItem('Team 2', '8')]),
getItem('Files', '9', <FileOutlined />),
];
const DashboardLayout = () => {
const [collapsed, setCollapsed] = useState(false);
const {
token: { colorBgContainer },
} = theme.useToken();
return (
<Layout
style={{
minHeight: '100vh',
}}
>
<Sider collapsible collapsed={collapsed} onCollapse={(value) => setCollapsed(value)}>
<div className="demo-logo-vertical" />
<Menu theme="dark" defaultSelectedKeys={['1']} mode="inline" items={items} />
</Sider>
<Layout>
<Header
style={{
padding: 0,
background: colorBgContainer,
}}
/>
<Content
style={{
margin: '0 16px',
}}
>
<Breadcrumb
style={{
margin: '16px 0',
}}
>
<Breadcrumb.Item>User</Breadcrumb.Item>
<Breadcrumb.Item>Bill</Breadcrumb.Item>
</Breadcrumb>
<div
style={{
padding: 24,
minHeight: 360,
background: colorBgContainer,
}}
>
Bill is a cat.
</div>
</Content>
<Footer
style={{
textAlign: 'center',
}}
>
Ant Design ©2023 Created by Ant UED
</Footer>
</Layout>
</Layout>
);
};
export default DashboardLayout;
এখানে আমরা admin page এ নেস্টেট লেআউট তৈরি করব । যেমন এখানে header and footer থাকনে এবং sidebar থাকবে ।
import DashboardLayout from '@/components/layouts/DashboardLayout';
import RootLayout from '@/components/layouts/RootLayout';
import React from 'react';
const AdminHomePage = () => {
return (
<div>
this is admin
</div>
);
};
export default AdminHomePage;
AdminHomePage.getLayout = function getLayout(page) {
return <RootLayout>
<DashboardLayout>
{page}
</DashboardLayout>
</RootLayout>
}
নেক্সট জেএস import
দুইভাবে করা যায় ।
একটা @ দিয়ে , এটা হচ্ছে absulute path
আরেকটা আছে ../component ../ দিয়ে ।
A relative path describes the location of a file relative to the current (working) directory*. An absolute path describes the location from the root directory
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}
Seo friendly use করার জন্য আমরা হেড কম্পোনেন্ট ইউজ করি ।
এভাবে আমরা উপরে টাইটলটা সেট করতে পারি
```js
<title>Next home page</title> ```আমরা meta tag
ইউজ করতে পারি এবং description এড করে দিতে পারি
এভাবে আমরা রলে দিতে পারি কোন পেইজে কি আছে । এটা দেখতে চাইলে right click
করে view source page
এ গিয়ে wrap
ক্লিক করতে হবে
return (
<div>
<Head>
<title>Next home page</title>
<meta name='home' description ="this page created by next page"></meta>
</Head>
<h1>this is home</h1>
</div>
);
ইমেজ দুইভাবে দেখা যায় । তবে next এর image component ব্যবহার করা যায় , এটা খুব স্পীড হয় ।
তবে মনে রাখতে হবে width , height , layout , এট্রিবিউট ইউজ করতে হবে ।
import Image from 'next/image';
import React from 'react';
const Album = () => {
return (
<div>
<img src='https://images.ctfassets.net/c63hsprlvlya/IacLLeOBR5WCvdCPqKuff/6860b5cc464c4f54703a2befa3f706b4/nextjs3.webp' alt=''></img>
<Image src="https://images.ctfassets.net/c63hsprlvlya/IacLLeOBR5WCvdCPqKuff/6860b5cc464c4f54703a2befa3f706b4/nextjs3.webp" width={400} height={300} layout='responsive'></Image>
</div>
);
};
export default Album;
ষবকিছু সেইম , জাস্ট এটা download করা
import Image from 'next/image';
import React from 'react';
import NextImage from '../assets/nextjs3.webp'
const Album = () => {
return (
<div>
<img src='https://images.ctfassets.net/c63hsprlvlya/IacLLeOBR5WCvdCPqKuff/6860b5cc464c4f54703a2befa3f706b4/nextjs3.webp' alt=''></img>
<Image src="https://images.ctfassets.net/c63hsprlvlya/IacLLeOBR5WCvdCPqKuff/6860b5cc464c4f54703a2befa3f706b4/nextjs3.webp" width={400} height={300} layout='responsive'></Image>
<Image src={NextImage} width={400} height={300} layout='responsive'></Image>
</div>
);
};
export default Album;
- public এখানে ইমেজ
- images এই ফোল্ডারের ভিতরে ডাউনলোয করা ইমেজ রাখা আছে ।
- image 1
- image 2
- image 3
- images এই ফোল্ডারের ভিতরে ডাউনলোয করা ইমেজ রাখা আছে ।
- src নিচের গুলো src folder এর ভিতরে
- assets
- images
- banner_images
- image1
- images
- components
- layout
- RootLayout.js এখানে হেডার এবং ফোটার আছে ।
- UI
- Banner.js এখানে banner slider দেয়া আছে
- layout
- pages
- index.js এখানে home দেয়া আছে ।
- about.js
- contact.js
- assets
এই নেক্সট জেএস এর মধ্যে একটা কায়েন্ট এবং সাভার রান হয় ।
কায়েন্ট সাইড রান করতে হয় npm run dev
দিয়ে ।
সাভার সাইড রান করতে হয় npm run json-server
দিয়ে
এখন json server install করতে npm i json-server
এখন package.json
লিখতে হবে "json-server": "json-server --watch db.json --port 5000",
এটা নিচে দেয়া হল
এখানে একটা বিষয় লক্ষ রাখতে হবে db.json
port 5000
এই দুইটা অবশ্যই দিতে হবে । db.json
মানে হচ্ছে এই প্রজেক্টে এই নামে একটা ফাইল আছে
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"json-server": "json-server --watch db.json --port 5000",
"lint": "next lint"
}
এখন কি কি ভাবে server access
করা যায়
http://localhost:5000/news
ডাটা আছে এরকম
{
"id": 1,
"title": "New Study Reveals Benefits of Regular Exercise",
"description": "A recent study conducted by experts in the field suggests that regular exercise can have numerous health benefits, including improved cardiovascular function and increased mental well-being.",
"author": "Healthline",
"release_date": "June 10, 2023",
"category": "Health",
"comment_count": 5,
"image_url": "/images/exercise_image.jpg"
},
মজার কথা হচ্ছে এভাবে একসেস করা যায় । ১ লিখে একসেস করা যায় ।
http://localhost:5000/news/1
আমরা জানি রিয়েক্টে ডাটা ফেস করার জন্য useEffect
ইউজ করতাম । এটা client side
কাজ করত । তাছাড়া এটা side effect
কাজ করত ।
নেক্সটা জেএস pre render
হয় server side
কাজ করার জন্য কিছু built in function দিয়ে দিয়েছে
তারা মধ্যে একটা হল getStaticProps
, নিচে এ সম্পকে আলোচনা করা হবে
নিচের কোডটি যে পেইজে ডাটা ফেস করব ওই পেইজে দিতে হবে
মনে রাখতে হবে এখানে console.log
করা যাবে না ।
- এটা
async fucntion
একটাpromise
রির্টান করবে
export const getStaticProps = async () => {
const res = await fetch("http://localhost:5000/news")
const data = await res.json()
console.log(data) // ekhne console.log hobe na
return {
props : {
allNews: data
}
}
}
console.log
করা যাবে client side
কোডের ভিতরে
নিচের কোডে ডাটা ফেস হচ্ছে । এখন HomePage
কম্পোনেন্টের ভিতেরে আমরা ডাটা পাচ্ছি ।
const HomePage = ({allNews}) => {
console.log(allNews , "this is news")
return (
<>
<Head>
<title>PH-News Portal</title>
<meta
name="description"
content="This is news portal of programming hero made by next-js"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<Banner />
</>
);
};
export default HomePage;
HomePage.getLayout = function getLayout(page) {
return <RootLayout>{page}</RootLayout>;
};
export const getStaticProps = async () => {
const res = await fetch("http://localhost:5000/news")
const data = await res.json()
return {
props : {
allNews : data
}
}
}
import { Card, Col, Row } from "antd";
import Image from "next/image";
import {
ArrowRightOutlined,
CalendarOutlined,
CommentOutlined,
ProfileOutlined,
} from "@ant-design/icons";
import Link from "next/link";
const AllNews = ({ allNews }) => {
const { Meta } = Card;
return (
<>
<h1
style={{
textAlign: "center",
fontSize: "50px",
margin: "30px 0px",
}}
>
#TODAY HIGHLIGHT
</h1>
<Row
gutter={{
xs: 8,
sm: 16,
md: 24,
lg: 32,
}}
>
{allNews?.map((news) => (
<Col key={news.id} className="gutter-row" xs={24} sm={24} md={12 } lg={6} >
<Card
hoverable
cover={
<Image
src={news?.image_url}
width={500}
height={200}
responsive
alt="news image"
/>
}
>
<Meta title={news?.title} />
<div
className="line"
style={{
height: "5px",
margin: "20px 0",
background: "#000",
width: "100%",
}}
></div>
<p
style={{
display: "flex",
justifyContent: "space-between",
width: "100%",
color: "gray",
margin: "10px 0px",
fontSize: "12px",
}}
>
<span>
<CalendarOutlined /> {news?.release_date}
</span>
<span>
<CommentOutlined /> {news?.comment_count} COMMENTS
</span>
<span>
<ProfileOutlined /> {news?.category}
</span>
</p>
<p style={{ fontSize: "15px" }}>
{news?.description.length > 100
? news?.description.slice(0, 70) + "..."
: news?.description}
</p>
<Link href={`/news/${news?.id}`}>
<p
style={{
fontSize: "15px",
marginTop: "20px",
backgroundColor: "black",
color: "white",
width: "100%",
padding: "2px 5px ",
fontWeight: "300",
letterSpacing: "3px",
textAlign: "center",
}}
>
Keep Reading <ArrowRightOutlined />
</p>
</Link>
</Card>
</Col>
))}
</Row>
</>
);
};
export default AllNews;
যখন আমরা production
এ যাবো ,যেমন :
npm run build
npm start
তখন db.json
এ কিছু চেন্জ করলে rebuild
ছাড়া এটা দেখাবে না
এটার সমাধান হচ্ছে ঐই পেইজে getStaticProps
কে revalidate
করা এটা ১০ সেকেন্ড পর হবে
export const getStaticProps = async () => {
const res = await fetch("http://localhost:5000/news")
const data = await res.json()
return {
props : {
allNews : data
},
revalidate : 10
}
}
আমরা root
ডাইরেক্টরি থেকে image
এর লোকেশন বলে দিতে হবে । সুতারাং public
ফোল্ডার হচ্ছে রোট directory যদি আমরা src ফোল্ডার থেকে assets ফোল্ডারে লোকেশন দিলে image দেখাব না যেমন :
"id": 1,
"title": "New Study Reveals Benefits of Regular Exercise",
"description": "A recent study conducted by experts in the field suggests that regular exercise can have numerous health benefits, including improved cardiovascular function and increased mental well-being.",
"author": "Healthline",
"release_date": "June 10, 2023",
"category": "Health",
"comment_count": 100,
"image_url": "/assets/images/404_Error_Page.png"
"image_url": "/assets/images/404_Error_Page.png"
এটা আসবে না । যেহেতু এটা assests folder থেকে
এখানে getStaticProps
হলো সব ডাটা গুলো নিয়ে আসতেছে । এখান থেকে map করে শুধুমাত্র id
নিয়ে নিচ্ছি ।
তারপর getStaticProps হলো params
গুলো নিয়ে নিবে ।
এখানে getStaticPaths
এর মধ্যে fallback : false
দ যদি id না থাকে তাহলে 404 not found বলবে
এখানে getStaticPaths
এর মধ্যে fallback : true
যখন large data
থাকবে যদি id না থাকে তাহলে লোডিং বলবে
এখানে getStaticPaths
এর মধ্যে fallback : blocking
যখন large data
থাকবে যদি id না থাকে তাহলে লোডিং বলবে
এখানে যে newsId
দিয়েছি কারণ filename এরকম দিয়েছি
export const getStaticPaths = async () => {
const res = await fetch(`http://localhost:5000/news/`);
const data = await res.json();
const paths = data.map((news) => ({
params: {
newsId: news.id
}
}))
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const {params} = context;
const res = await fetch(`http://localhost:5000/news/${params.newsId}`);
const data = await res.json();
return {
props : {
news : data,
}
}
}
এই যে আমরা getStaticProps
and getStaticPaths
ব্যবহারা করে ডাইনামিক পেইজটা করেছি এটাকে বলা হয় SSG (static side generation) অথাৎ build
টাইমে আমাদের ডাটা create হচ্ছে । কিন্তু ্এখানে একটা ইস্যু আছে । আমাদের ডাটা প্রতিসেকেন্ডে আপডেট হচ্ছে । যার ফলে একজন ইউজার আপডেট দেখতে পাবে না । এখন প্রশ্ন আসতে পারে । ভাই আমরা revalidate
ইউজ করি , কিন্তু তখন ও সেকেন্ড দিতে হয় ।
তাই এজন্য আমরা ইউজ করবো SSR
(Server side rendering) এখানে request টাইমে আমরা ডাটা পেয়ে যাবো ।
এখন আমরা index.js and [nextid].js
চেন্জ করে নিচের মতো করে দিয়েছি ।
export const getServerSideProps = async () => {
const res = await fetch("http://localhost:5000/news")
const data = await res.json()
return {
props : {
allNews : data
}
}
}
এখানে ইউজারের রিকোয়েস্টের অনুসারে ইনস্টেন্ট সাভার থেকে ডাটা নিয়ে আসছি । এবং ডাইনামিক কনটেন্টটা পেয়ে যাচ্ছি । এটা static data তৈরি হচ্ছে না , পুরোটা server side data তৈরি হচ্ছে । যার ফলে SEO friendly হচ্ছে ।
এই same কাজটা useEffect দিয়ে করতে পারতাম , client side rendering হয়ে যতো , যার কারণে seo friendly behavior টা পেতাম না ।
এটা প্রজেক্টা উপর ডিপেন্ড করে । প্রতিনিয়ত পোস্ট আপডেট হবে তখন আমরা server side rendering ইউজ করতে হবে । আর যখন আমরা ১০ সেকেন্ড পর পর বা ২০ সেকেন্ড পর পর আপডেট হবে তখন আমরা static side generation ইউজ করব ।
Dashboard
and user dashboar , admin dashborad
এখানে server side rendering প্রয়োজন নেই । client side generation
ইউজ করব ।
- src
- redux
- store.js
- page
- _app.js
- redux
import { configureStore } from '@reduxjs/toolkit'
import { apiSlice } from './api/api'
export const store = configureStore({
reducer: {
[apiSlice.reducerPath]: apiSlice.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(apiSlice.middleware),
})
এখানে store , provider কে কানেক্ট করে দিছি ।
import { store } from '@/redux/store';
import '@/styles/globals.css'
import { Provider } from 'react-redux';
export default function App({ Component, pageProps }) {
const getLayout = Component.getLayout || ((page) => page);
return <Provider store={store}>
{ getLayout(<Component {...pageProps} />)}
</Provider>;
}
- api
- apiSlice
- Rtk query link
// Need to use the React-specific entry point to import createApi
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
// Define a service using a base URL and expected endpoints
export const apiSlice = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:5000' }),
endpoints: (builder) => ({
getNewes: builder.query({
query: () => ({
url: '/news',
}),
})
}),
})
// Export hooks for usage in functional components, which are
// auto-generated based on the defined endpoints
export const { useGetNewesQuery } = apiSlice
তারপর এই hook টাকে কল করলাম । এই hook চারটা ডাটা রিটান করে ।
মনে রাখতে হবে এটা initially ডাটা undefine
const { data , isError , isLoading , error } = useGetNewesQuery();
console.log(data)
আমাদের website performance
বৃদ্ধি করতে । কোন content যেটা আসতে সময় লাগছে । আমরা চাচ্ছি ওই time টাতে একটা Loading state
দেখাবে । তখন আমরা Dynamic import
or lazy loading
বলে থাকি
আমরা যে কম্পোনেন্টে loading দেখানে সেই component এর লোকেশন দিবো । তারপর তার নাম দিতে হবে
const DynamicLoading = dynamic(
() => import('@/components/UI/Banner'),
{
loading: () => <h1>Loading...</h1>,
}
)
<DynamicLoading />
Install mongodb
npm i mongodb
create database
প্রথমে mongodb
তে লগইন করতে হবে । তারপর database access
গিয়ে create new database user
এ ক্লিক দিতে হবে । তারপর ডাটাবেজ নেম এবং পাসওযাড় দিতে হবে । ডাটাবেজ নেম ও পাসওর্য়াড় মনে রাখতে হবে
তারপর database
ক্লিক দিতে হবে । তারপর browse Collection
এ গিয়ে create database
গিয়ে ডিবিনেম, কালেকশন নেম দিতে হবে ।
database
ক্লিক দিয়ে connect
এ ক্লিক দিয়ে drivers
তারপর নিচের কোড কপি করতে হবে ।
insert json data এখানে browse collection এ গিয়ে insert document এ ক্লিক করে array আকারে insert করতে হবে
const { MongoClient, ServerApiVersion } = require('mongodb');
const uri = "mongodb+srv://<username>:<password>@cluster0.wg8wdsp.mongodb.net/?retryWrites=true&w=majority";
// Create a MongoClient with a MongoClientOptions object to set the Stable API version
const client = new MongoClient(uri, {
serverApi: {
version: ServerApiVersion.v1,
strict: true,
deprecationErrors: true,
}
});
async function run() {
try {
// Connect the client to the server (optional starting in v4.7)
await client.connect();
// Send a ping to confirm a successful connection
await client.db("admin").command({ ping: 1 });
console.log("Pinged your deployment. You successfully connected to MongoDB!");
} finally {
// Ensures that the client will close when you finish/error
await client.close();
}
}
run().catch(console.dir);
const { MongoClient, ServerApiVersion } = require('mongodb');
const uri = "mongodb+srv://news:[email protected]/news?retryWrites=true&w=majority";
// Create a MongoClient with a MongoClientOptions object to set the Stable API version
const client = new MongoClient(uri, {
serverApi: {
version: ServerApiVersion.v1,
strict: true,
deprecationErrors: true,
}
});
async function run(req ,res) {
// Connect the client to the server (optional starting in v4.7)
await client.connect();
// Send a ping to confirm a successful connection
console.log("connection established")
const newsConnection = client.db("news").collection("news");
if(req.method === "GET"){
const news = await newsConnection.find({}).toArray()
res.send({message:'success',status: 200, data : news});
}
if (req.method === "POST") {
const news = req.body;
const result = await newsCollection.insertOne(news);
res.json(result);
}
}
export default run;
in create.js
import { useForm } from "react-hook-form";
import styles from "@/styles/Create.module.css";
const CreateNews = () => {
const { register, handleSubmit } = useForm();
const onSubmit = (data) => {
fetch("/api/news", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(data),
})
.then((res) => res.json())
.then((data) => {
if (data.insertedId) {
alert("News Successfully Created");
}
});
};
return (
<div>
<form
className={styles.form}
onSubmit={handleSubmit(onSubmit)}
name="form_item_path"
layout="vertical"
style={{
width: "50%",
margin: "50px auto",
}}
>
<input
{...register("id")}
placeholder="Id"
style={{ marginBottom: "10px" }}
/>
<input {...register("title")} placeholder="Title" />
<input
{...register("description")}
placeholder="Description"
style={{ margin: "10px 0px" }}
/>
<input {...register("author")} placeholder="Author" />
<input
{...register("release_date")}
placeholder="Release Date"
type="date"
style={{ margin: "10px 0px" }}
/>
<input {...register("category")} placeholder="Category" />
<input
{...register("comment_count")}
placeholder="Number of Comments"
type="number"
style={{ margin: "10px 0px" }}
/>
<input {...register("image_url")} placeholder="Image URL" />
<input
type="submit"
value="Create News"
style={{ margin: "10px 0px", width: "100%" }}
/>
</form>
</div>
);
};
export default CreateNews;
আমরা react
এর মধ্যে যখন কোন কম্পোনেন্টের জ্ন্য css
এপ্লাই করতাম তখন ওই style টা সব কম্পোনেন্টে apply হয়ে যেতো আথাৎ overflow হয়ে যতো । এটা থামানোর জন্য next js এ আছে css module support
- styles
- About.Modules.css
- Contact.Modules.css in About.Modules.css
.heading{
font-size: 50;
background-color: brown;
}
in Contact.Modules.css
.heading{
font-size: 50;
background-color: green;
}
কিভাবে এপ্রাই করব
import styles from "@/styles/Contact.modules.css"
<h1 className={styles.heading}> Developer is sleeping....! Contact Us page coming soon....!</h1>
First, run the development server:
npm i
npm install next-auth
npm install firebase
npm i react-firebase-hooks
npm run dev
# or
yarn dev
# or
pnpm dev
Next js এর প্রৌভাইড করা অথেনটিকেশন সিস্টেম আছে https://next-auth.js.org/getting-started/example
এই লিংক থেকে next-auth install করার পর নিচ থকে কোড কপি করে ।
folder
auth
and [...nextauth].js
spread operator দিয়ে catch all route
file সেইম দিতে হবে
- page
- api
- auth
- [...nextauth].js
- auth
- api
import NextAuth from "next-auth"
import GithubProvider from "next-auth/providers/github"
export const authOptions = {
// Configure one or more authentication providers
providers: [
],
}
export default NextAuth(authOptions)
এখানে _app.js এর সাথে কানেক্ট করতে হবে ।
import { SessionProvider } from "next-auth/react"
এখানে SessionProvider wrap
করে দিতে হবে । এবং session এট্রিভিউট এর ভিতর pageProps
থেকে পাওয়া session
কে পাস করে দিতে হবে ।
import '@/styles/globals.css'
import Navbar from "@/components/Layout/Navbar";
import { SessionProvider } from "next-auth/react"
export default function App({ Component, pageProps }) {
return (
<SessionProvider session={pageProps.session}>
<>
<Navbar />
<Component {...pageProps} />
</>
</SessionProvider>
);
}
প্রথমে এই লিংকে গিয়ে https://next-auth.js.org/providers/github provider
এর ভিতরে github
তারপর github
প্রোফাইলে গিয়ে setting => development setting => OAuth apps
অথবা https://github.com/settings/developers
এখানে regiser app
এ ক্লিক দিয়ে application name এটা যে কোন কিছু , application url এর মধ্যে http://localhost:3000/, application callback এ দিতে হবে http://localhost:3000/,
দিয়ে রেজিস্টার করে client id and client secret
নিয়ে .env
file create বসাতে হবে ।
import NextAuth from "next-auth"
import GithubProvider from "next-auth/providers/github"
export const authOptions = {
// Configure one or more authentication providers
providers: [
GithubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
],
}
export default NextAuth(authOptions)
এখন login.js এর মথ্যে কল করতে হবে ।
import { signIn } from "next-auth/react";
<GithubOutlined onClick={() => signIn("github")}/>
।এবার লগইন হয়ে গেলে ওটা session
এ রাখতে হবে
- commponent
- layout
- Navbar.js
- layout
import { useSession, signOut } from "next-auth/react"
const Navbar = () => {
const { data: session } = useSession()
console.log("from header", session)
{session?.user? <items>
<Button type="primary" danger>
Logout
</Button>
</items> :
<Link style={{ textDecoration: "none", color: "white" }} href="/login">
<items>Login</items>
</Link>}
}
জাস্ট signOut ফাংশনকে কল করতে হবে
- in Navber.js
import { useSession, signOut } from "next-auth/react"
<Button onClick={() => signOut()} type="primary" danger>
Logout
</Button>
জাস্ট sign in
এর ভিতরে একটা object
এর আকরে callback টা দিতে হবে ।
- in login page
<GithubOutlined onClick={() => signIn("github" , {
callbackUrl: "http://localhost:3000/"
})}/>
এখানে name , email সব দেখা যাবে
import { useSession } from "next-auth/react"
const HomePage = () => {
const {data : session} = useSession();
<h1 style={{ textAlign: "center" }}>Logged in user : { session?.user?.name}</h1>
}
https://next-auth.js.org/providers/google
প্রথমে এই লিংকে https://console.developers.google.com/apis/credentials গিয়ে প্রজেক্ট ক্রিয়েট করতে হবে ।
তারপর auth constant screen
configure করতে হবে ।
তারপর create credentials
করতে হবে ।
client id and client secret কপি করতে হবে । .env
file সেট করতে হবে
- api
- auth
- [...nextauth].js
- auth
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
- page
- login.js
<GoogleOutlined onClick={() => signIn("google" , {
callbackUrl: "http://localhost:3000/"
})}/>
আমরা যখন react
private route করতাম তখন কম্পোনেন্ট wrap করতে হতো ।
এখন আমরা next js এ মাত্র দুই লাইন কোড লিখে private route
করতে পারি ।
https://next-auth.js.org/configuration/nextjs#middleware এ যেতে হবে আথবা middleware
সার্চ করে যেতে হবে ।
- src
- middleware.js
এখানে যত ROUTE
আমরা প্রটেক্ট করতে চাই , তত গুলো array
এর ভিতরে রাখবো
export { default } from "next-auth/middleware"
export const config = { matcher: ["/profile"] }
এখন যদি আমরা login
করা বা না করা থাকলে ও profile
যাই তাহলে internal server error
দিবে
এটা যদি আমরা login
url এ দেখতে চাই তাহলে
NEXTAUTH_URL = http://localhost:5000
NEXTAUTH_SECRET = abc
এখনো হবে না , তাদের login
ui টা দেখাবে ।
pages : {
signIn : "/login"
}
এখন আমাদের ui তে দেখাচ্ছে যদি profile
ক্লিক করি তাহলে authorized
না হলে লগইনে নিয়ে যাবে ।
npm install react-hook-form
// এটা import করতে হবে
import { useForm } from "react-hook-form"
// এটা রিটানের উপরে দিতে হবে
const {
register,
handleSubmit,
formState: { errors },
} = useForm()
const onSubmit = (data) => console.log(data)
//এটা রিটানের ভিতরে দিতে হবে --------------------------------
<form onSubmit={handleSubmit(onSubmit)}>
<label htmlFor="">Your Email</label>
<input type="email" {...register("email", { required: true })}/>
{errors.email && <p style={{color : "red"}}>this field is required</p>}
<label htmlFor="">Your Password</label>
<input type="password" {...register("password" , { required: true })}/>
{errors.password && <p style={{color : "red"}} >this field is required</p>}
<button type="submit">Login</button>
</form>
রথমে firebase গিয়ে https://console.firebase.google.com/ new project ক্রিয়েট করতে হবে । web এর জন্য প্রজেক্ট করতে হবে । ২০ সেকেন্ড সময় লাগে ।
তারপর authentication
এ ক্লিক দিয়ে get started
এ ক্লিক দিয়ে Email and password``enable
করে দিতে হবে ।
তারপর project setting
গিয়ে configuration
টা নিয়ে নিতে হবে ।
npm install firebase
npm i react-firebase-hooks
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
// Initialize Firebase
const app = initializeApp(firebaseConfig);
Shit + tab
দিলে alignment হয়ে যাবে ।
যে কোন কিছু select
করে Ctrl + shtft + L
যেইটা সিলেক্ট করা হয়েছে সব হয়ে যাবে ।
একটা symble
থেকে শেষে যেতে চাইলে Shift + end
অথবা শুরুতে যেতে চাইলে Shift + start
ক্লিক দিয়ে করতে হবে ।
যেমন এখানে =
কে ক্লিক দিয়ে সব সমান সিলেক্ট করে এখান থেকে শুরু বা শেষে যেতে পারব select
and copy
, delete
,করতে পারব ।
Next_apiKey = AIzaSyAZSnt6AcOfRYnW
Next_authDomain = next-auth
Next_projectId = next-aut
Next_storageBucket = next-aut
Next_messagingSenderId = 83081401299
Next_appId = 1:83081401299:web
যেহেতু firebase hook
install দিয়ছি । তাই আমরা hook
ব্যবহার করব ।
যখন সাবমিট করব তখন firebase
এ সেভ হবে ।
in login.js
import { useCreateUserWithEmailAndPassword } from 'react-firebase-hooks/auth';
import auth from "@/firebase/firebase.auth.js";
const LoginPage = () => {
const [
createUserWithEmailAndPassword,
user,
loading,
error,
] = useCreateUserWithEmailAndPassword(auth);
const onSubmit = (data) => {
createUserWithEmailAndPassword(data.email, data.password)
}
এখন স্টেট থেকে user
কে পেয়ে যাবো ।
import Head from "next/head";
import { useSession } from "next-auth/react"
import { useAuthState } from "react-firebase-hooks/auth";
import auth from "@/firebase/firebase.auth";
const HomePage = () => {
const {data : session} = useSession();
const [user , loading , error] = useAuthState(auth)
return (
<div>
<Head>
<title>Next Auth</title>
</Head>
<h1 style={{ textAlign: "center", marginTop:"10%" }}>Welcome To Next Auth Home Page</h1>
{user?.email && <h1 style={{ textAlign: "center" }}>Logged in user : { user?.email}</h1>}
</div>
);
};
export default HomePage;