Skip to content

AriFullah3202/core-next

Repository files navigation

This is a Next.js project bootstrapped with create-next-app.

Lets Start our journey with Nextjs

এখানে আমাদের জানতে হবে । next js কি ? কেন ব্যবহার করতে হয় ।

Next js হচ্ছে react এর framework . React with supper power . যা React এর সাথে combine করে হয়েছে ।

Super Power এর মধ্যে কি আছে ।
  • 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 js কেন ইউজ করব ।

React হচ্ছে library এবং Next js হচ্ছ একটি framework
আর next documantaion এ বলছে full stack করতে চাইলৈ next js ইউজ করতে । আর library হচ্চে ছোটা তিনিস framework হচ্ছে বড় তিনিস ।
আমরা রিযেক্টে fulll stack project করতে thired party লাইব্রেরি ইউজ করতে হতৌ । যেমণ : firebase , react router , express
next js এর মধ্যে Built in Routing System , Api Routes , Next Auth আছে ।
next js
  • next js preRenderg
    • Static side Generation (SSG)
    • Server side Rendering (SSR)
  • react js Client side Rendering
এবার বলা যায় Rendering কি
html , css , javaScript কে convert করে একটা ইউজার জন্য দৃশ্যমান layout make করা

Clear concept of pre-rendering and 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 টা কেন কলা হয় ।

এটা build time এ তৈরি হচ্ছে ।
server side rendering টা user এর requst অনুসারে হচ্ছে ।

Getting Started and install some packages

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

How to create Next js appS

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

folder structur e সবচেয়ে গুরুত্বপূর্ণ হচ্ছে _app.js

যেখান থেকে component গুলো generate হয়ে ui তে দেখাচ্ছে । এটা না থাকলে হবে না

তারপর _app.js এরপর index.js এটা সেকেন্ড মেইন ফাইল ।

pages ফোল্ডারে _app.js and index.js টা অবশ্যই লাগবে ।

docuent.js টা ডিলিট করে দিলাম ।

Key featucre of next js with file system routing

এবার একটা file create করতে হবে ।

about.js

import React from 'react'

export default function () {
  return (
    <div>this is about page</div>
  )
}

এবার যদি আমরা hit করি

http://localhost:3000/about

মনে রাখা প্রয়োজন এটা file এর নাম অনুসারে লিখতে হবে । যেমন : about

আগে আমরা রিযেক্টে , এভাবে লিখতাম , এখন next js জাস্ট ফাইলের নাম ধরে ডাক দিলাম

const route = [
   {
      path : "/home",
      component : home
   }
]

Nested route and dynamic route

first Nested route

একটা 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

এখন কথা হল , article home page কিভাবে করব ?

জাস্ট ariticle folder e গিয়ে index.js নামে file create করতে হবে ।

import React from 'react';

const index = () => {
    return (
        <div>
            this is home page 
        </div>
    );
};

export default index;

মনে রাখতে হবে index.js নামে দিতে হবে ।

তাহলে url হবে । http://localhost:3000/article/

এভাবে আমরা nested folder create করতে পাবি ।
  • article
    • post
      • post.js
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 করতে পারি ।

জাস্ট index.js file create করতে পারি

dynamic route

dynamic route করতে কি করতে হবে ।

প্রথমে একটা ফোল্ডার create করি । নাম দিলাম product
[productId].js দিতে হবে

মনে রাখতে হবে [] braket দিতে হবে ।

rsc দিয়ে file create করার সাথে সাথে নাম চেন্জ করতে হবে

এবং import করতে হবে useRouter hook

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;

Catch all route

catch all route মানে হল ,
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 করা যেতে পারে ।

এটাকে বলা হয় next js এর ভাষায় catch all route

এখানে অনেক route দিলে কাজ করবে

এটা কিভাবে করব?

এজন্য ফাইলের দিতে হবে

[...slug].js এখানে তিনটা ডট দিতে হবে ।

for example

  • news
    • [...slug].js
import React from 'react';

const FilterIng = () => {
    return (
        <div>
             this the filter ing
        </div>
    );
};

export default FilterIng;

Custom 404 file create

এতন্য file name দিতে হবে

  • page
    • 404.js
অবশ্যই 404.js লিখতে হবে । এট name convention

Ant design setup

npm install antd --save
navigate to home
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;

Automatic home after 5 second

এটা useRouter hook দিয়ে করা হচ্ছে ।

setTimeout function এ বলে দিছি , ২ সেকেন্ড পরে কোথায় যাবে ।

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;

Explore simple layout system

প্রথমে একটা component বানাতে হবে , এখানে header , navbar , footer আছে ।

  • 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} />)
}

যে component আমরা header , footer , navbar দিতে চাই । সে component এর নিচে

নিচের ফাইলটা দিতে হবে ।

**এখানে আমরা getLayoutproperty কে এবং funcion কে assign করে দিচ্ছি , যার নাম হচ্ছে getLayout ফাংশন ।

Home.getLayout = function getLayout(page) {
  return (
    <RootLayout>
      {page}
    </RootLayout>
  )
}

Explore Dashboard layout and Nested layout system

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;

Nested layout

এখানে আমরা 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>
}

Using Head components for better SEO , Image Component , Import alias

Import Alias

নেক্সট জেএস 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

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>
  );

image optimization

ইমেজ দুইভাবে দেখা যায় । তবে 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;

Local image uses , downloaded image

ষবকিছু সেইম , জাস্ট এটা 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;

Folder structure

  • public এখানে ইমেজ
    • images এই ফোল্ডারের ভিতরে ডাউনলোয করা ইমেজ রাখা আছে ।
      • image 1
      • image 2
      • image 3
  • src নিচের গুলো src folder এর ভিতরে
    • assets
      • images
        • banner_images
        • image1
    • components
      • layout
        • RootLayout.js এখানে হেডার এবং ফোটার আছে ।
      • UI
        • Banner.js এখানে banner slider দেয়া আছে
    • pages
      • index.js এখানে home দেয়া আছে ।
      • about.js
      • contact.js

run json server

এই নেক্সট জেএস এর মধ্যে একটা কায়েন্ট এবং সাভার রান হয় ।

কায়েন্ট সাইড রান করতে হয় 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

Data fatching with getStaticProps

আমরা জানি রিয়েক্টে ডাটা ফেস করার জন্য 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
    }
  }
}

Responsive design for antDesign card

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;

Note and issus in getStaticProps

যখন আমরা 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
  }
}

why we save image in public folder in next.js

আমরা 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 থেকে

Specific data form json

এখানে 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 টা পেতাম না ।

when we use server side rendering and static side ‌generation

এটা প্রজেক্টা উপর ডিপেন্ড করে । প্রতিনিয়ত পোস্ট আপডেট হবে তখন আমরা server side rendering ইউজ করতে হবে । আর যখন আমরা ১০ সেকেন্ড পর পর বা ২০ সেকেন্ড পর পর আপডেট হবে তখন আমরা static side generation ইউজ করব ।

Dashboard and user dashboar , admin dashborad এখানে server side rendering প্রয়োজন নেই । client side generation ইউজ করব ।

Technical Breakdown of Clients side data faching usin RTK Query

  • src
    • redux
      • store.js
    • page
      • _app.js

Store.js

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),
})

_app.js

এখানে 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>;
}

Create api slice

  • 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)

Dynamic import ( lazy loading) No SSR

আমাদের 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 create database insert json data into mongodb database and connect to mongodb

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);

Get and Post data into mongodb

const { MongoClient, ServerApiVersion } = require('mongodb');
const uri = "mongodb+srv://news:arif123@cluster0.wg8wdsp.mongodb.net/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;

Using React hook to post data

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;

Css Module support in next js

আমরা 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>

Getting Started Next Auth

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
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>
  );
}

Implement Github authentication

প্রথমে এই লিংকে গিয়ে 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")}/>

User in Session

।এবার লগইন হয়ে গেলে ওটা session এ রাখতে হবে

  • commponent
    • layout
      • Navbar.js
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>}
}

Sign out user

জাস্ট signOut ফাংশনকে কল করতে হবে

  • in Navber.js
  import { useSession, signOut } from "next-auth/react"
  <Button onClick={() => signOut()} type="primary" danger>
            Logout
          </Button>
          

Redirect after sign in

জাস্ট sign in এর ভিতরে একটা object এর আকরে callback টা দিতে হবে ।

  • in login page
  <GithubOutlined onClick={() => signIn("github" , {
            callbackUrl: "http://localhost:3000/"
          })}/>

Show user in profile

এখানে 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>
}

Google authentication in next

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
 GoogleProvider({
        clientId: process.env.GOOGLE_ID,
        clientSecret: process.env.GOOGLE_SECRET,
      }),
  • page
    • login.js
 <GoogleOutlined onClick={() => signIn("google" , {
            callbackUrl: "http://localhost:3000/"
          })}/>

Protect a route from unauthorized user using middleware

আমরা যখন 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না হলে লগইনে নিয়ে যাবে ।

Implementations email and password based authentication with firebase authentication

Using React hook form

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>

Now integrate the firebase

রথমে 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);

multi cursor alignment

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;

About

নেক্সট জেএস বাংলা রিসোর্স পড়তে পারেন ।।

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published