article

Wednesday, April 26, 2023

ReactJS Python Flask Infinite Scroll Pagination | SQLAlchemy Mysql

ReactJS Python Flask Infinite Scroll Pagination | SQLAlchemy Mysql

Python Flask 

https://flask.palletsprojects.com/en/2.2.x/installation/
 
Create an environment
C:\flask_dev>py -3 -m venv venv

Activate the environment
C:\flask_dev>venv\Scripts\activate

Install Flask
venv C:\flask_dev>pip install Flask
C:\flask_dev\flaskreact\app.py

Install requirements

Flask-SQLAlchemy
Flask-SQLAlchemy is an extension for Flask that adds support for SQLAlchemy to your application.
https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/

(venv) PS C:\flask_dev\flaskreact>pip install -U Flask-SQLAlchemy

Flask-Cors
A Flask extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible.
https://pypi.org/project/Flask-Cors/

(venv) PS C:\flask_dev\flaskreact>pip install -U flask-cors

C:\flask_dev\flaskreact\app.py
 
#C:\flask_dev\flaskreact\app.py
from flask import Flask, request, jsonify
from flask_cors import CORS, cross_origin #ModuleNotFoundError: No module named 'flask_cors' = pip install Flask-Cors
 
from models import db, User
 
app = Flask(__name__)
 
app.config['SECRET_KEY'] = 'cairocoders-ednalan'
#app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///flaskdb.db'
# Databse configuration mysql                             Username:password@hostname/databasename
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:''@localhost/flaskreact'
 
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_ECHO = True
 
CORS(app, supports_credentials=True)
 
db.init_app(app)
    
with app.app_context():
    db.create_all()
 
@app.route("/")
def hello_world():
    return "Hello, World!"
 
@app.route('/users/<int:page>/<int:per_page>', methods=['GET']) #http://127.0.0.1:5000/users/1/4
def posts(page=1, per_page=10):
  
    total = User.query.count()
    print(total)
  
    posts = User.query.order_by(User.id.asc())  
    posts = posts.paginate(page=page, per_page=per_page)
  
    return jsonify({
        'total': total,
        'page': page,
        'per_page': per_page,
        'data': [{
            'id': p.id,
            'fullname': p.name,
            'email': p.email,
            'password': p.password,
            'photo': p.photo
        } for p in posts.items]
    })
 
if __name__ == "__main__":
    app.run(debug=True)
C:\flask_dev\flaskreact\models.py
 
#C:\flask_dev\flaskreact\models.py
from flask_sqlalchemy import SQLAlchemy
from uuid import uuid4
   
db = SQLAlchemy()
   
def get_uuid():
    return uuid4().hex
   
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.String(11), primary_key=True, unique=True, default=get_uuid)
    name = db.Column(db.String(150), unique=True)
    email = db.Column(db.String(150), unique=True)
    password = db.Column(db.Text, nullable=False)
    photo = db.Column(db.String(150), unique=True)
run (venv) C:\flask_dev\flaskreact>flask run
http://127.0.0.1:5000/users/1/4

users.sql : https://github.com/cairocodes/cairocoders/blob/main/users.sql

React JS
https://create-react-app.dev/

Create Project
C:\react-js>npx create-react-app myreactdev

Run
C:\react-js\myreactdev> npm start
C:\react-js\myreactdev\src\App.js
//C:\react-js\myreactdev\src\App.js
import React, { useEffect, useState } from "react";
import "./App.css";
  
import InfiniteScroll from "react-infinite-scroll-component"; //npm install --save react-infinite-scroll-component = https://github.com/ankeetmaini/react-infinite-scroll-component
import Users from "./components/Users";
import Loader from "./components/Loader";
import End from "./components/End";

function App() {
  const [items, setItems] = useState([]);

  const [hasMore, sethasMore] = useState(true);

  const [page, setpage] = useState(2);

  const perPage = 8;

  useEffect(() => {
    const getUsers = async () => {
      const res = await fetch(
        `http://127.0.0.1:5000/users/1/${perPage}`
      );
      const usersdata = await res.json();
      setItems(usersdata.data);
      console.log(usersdata.data);
    };

    getUsers();
  }, []);

  const fetchUsers = async () => {
    const res = await fetch(
      `http://127.0.0.1:5000/users/${page}/${perPage}`
    );
    const scrolldata = await res.json();
    return scrolldata.data;
  };

  const fetchData = async () => {
    const usersServer = await fetchUsers();

    setItems([...items, ...usersServer]);
    if (usersServer.length === 0 || usersServer.length < 20) {
      sethasMore(false);
    }
    setpage(page + 1);
  };
  return (
    <InfiniteScroll
      dataLength={items.length} //render next data
      next={fetchData}
      hasMore={hasMore}
      loader={<Loader />}
      endMessage={<End />}
    >
      <div className="container">
        <div className="row justify-content-center">
          <div className="col-12 col-sm-8 col-lg-6">
            <div className="section_heading text-center wow fadeInUp">
              <h3>ReactJS Python Flask Infinite Scroll Pagination | SQLAlchemy Mysql</h3>
              <div className="line"></div>
            </div>
          </div>
        </div>

        <div className="row" style={{padding: 20}}>
          {items.map((item) => {
            return <Users key={item.id} item={item} />;
          })}
        </div>

      </div>
    </InfiniteScroll>
  );
}

export default App;
C:\react-js\myreactdev\src\components\Users.js
//C:\react-js\myreactdev\src\components\Users.js
import React, { } from "react";
  
function Users({item: { fullname, email, photo }}) {
    return (
      <div className="col-12 col-sm-6 col-lg-3">
          <div className="single_advisor_profile wow fadeInUp">
              <div className="advisor_thumb"> <img alt="pic" src={photo} width="315" height="315"/></div>
              <div className="single_advisor_details_info">
                    <h6>{fullname}</h6>
                    <p className="designation">{email}</p>
              </div>
        </div>
      </div>
    )
}

export default Users
C:\react-js\myreactdev\src\components\Loader.js
//C:\react-js\myreactdev\src\components\Loader.js
import React, { } from "react";
  
function Loader() {
    return (
        <div className="container">
          <div className="row ">
            <div className="col d-flex justify-content-center">
              
            <div class="spinner-border spin" role="status">
            <span class="visually-hidden">Loading...</span>
            </div>

            </div>
          </div>
        </div>
    )
}

export default Loader
C:\react-js\myreactdev\src\components\End.js
//C:\react-js\myreactdev\src\components\End.js
import React, { } from "react";
  
function End() {
    return (
        <p style={{ textAlign: "center" }}>
          <b>End</b>
        </p>
    )
}

export default End
react-js\myreactdev\src\App.css
//react-js\myreactdev\src\App.css
 body{margin-top:20px;
background:#eee;
}
.single_advisor_profile {
    position: relative;
    margin-bottom: 50px;
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    z-index: 1;
    border-radius: 15px;
    -webkit-box-shadow: 0 0.25rem 1rem 0 rgba(47, 91, 234, 0.125);
    box-shadow: 0 0.25rem 1rem 0 rgba(47, 91, 234, 0.125);
}
.single_advisor_profile .advisor_thumb {
    position: relative;
    z-index: 1;
    border-radius: 15px 15px 0 0;
    margin: 0 auto;
    padding: 30px 30px 0 30px;
    background-color: #3f43fd;
    overflow: hidden;
}
.single_advisor_profile .advisor_thumb::after {
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    position: absolute;
    width: 150%;
    height: 80px;
    bottom: -45px;
    left: -25%;
    content: "";
    background-color: #ffffff;
    -webkit-transform: rotate(-15deg);
    transform: rotate(-15deg);
}
@media only screen and (max-width: 575px) {
    .single_advisor_profile .advisor_thumb::after {
        height: 160px;
        bottom: -90px;
    }
}
.single_advisor_profile .single_advisor_details_info {
    position: relative;
    z-index: 1;
    padding: 30px;
    text-align: right;
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    border-radius: 0 0 15px 15px;
    background-color: #ffffff;
}
.single_advisor_profile .single_advisor_details_info::after {
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    position: absolute;
    z-index: 1;
    width: 50px;
    height: 3px;
    background-color: #3f43fd;
    content: "";
    top: 12px;
    right: 30px;
}
.single_advisor_profile .single_advisor_details_info h6 {
    margin-bottom: 0.25rem;
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
}
@media only screen and (min-width: 768px) and (max-width: 991px) {
    .single_advisor_profile .single_advisor_details_info h6 {
        font-size: 14px;
    }
}
.single_advisor_profile .single_advisor_details_info p {
    -webkit-transition-duration: 500ms;
    transition-duration: 500ms;
    margin-bottom: 0;
    font-size: 14px;
}
@media only screen and (min-width: 768px) and (max-width: 991px) {
    .single_advisor_profile .single_advisor_details_info p {
        font-size: 12px;
    }
}
.single_advisor_profile:hover .advisor_thumb::after,
.single_advisor_profile:focus .advisor_thumb::after {
    background-color: #070a57;
}
.single_advisor_profile:hover .single_advisor_details_info,
.single_advisor_profile:focus .single_advisor_details_info {
    background-color: #070a57;
}
.single_advisor_profile:hover .single_advisor_details_info::after,
.single_advisor_profile:focus .single_advisor_details_info::after {
    background-color: #ffffff;
}
.single_advisor_profile:hover .single_advisor_details_info h6,
.single_advisor_profile:focus .single_advisor_details_info h6 {
    color: #ffffff;
}
.single_advisor_profile:hover .single_advisor_details_info p,
.single_advisor_profile:focus .single_advisor_details_info p {
    color: #ffffff;
}

.spin {
    width: 3rem; height: 3rem;
}
react-js\myreactdev\public\index.html
//react-js\myreactdev\public\index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"/>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
Run C:\react-j\myreactdev>npm start
http://localhost:3000/

Related Post