- 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 devnpx create-next app@latest
এখানে এই কমান্ড দেয়ার পর প্রজেক্ট নেম জিঙ্গেস করবে , eslint , tailwind ব্যবহার করবে কিনা জিঙ্গেস করবে ।
cd my-app
npm run dev
npm install antd -savethen 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 --saveimport { 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 mongodbcreate 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 devNext 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;