├── README.md ├── postcss.config.js ├── vite.config.js ├── tailwind.config.js ├── src ├── main.jsx ├── App.css ├── index.css ├── App.jsx └── assets │ └── react.svg ├── .gitignore ├── index.html ├── backend └── server.js ├── .eslintrc.cjs ├── package.json ├── .github └── workflows │ └── static.yml └── public └── vite.svg /README.md: -------------------------------------------------------------------------------- 1 | # Connecting-React-to-Express-Backend 2 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: [ 4 | "./index.html", 5 | "./src/**/*.{js,ts,jsx,tsx}", 6 | ], 7 | theme: { 8 | extend: {}, 9 | }, 10 | plugins: [], 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.jsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | /* // await delay(2); 9 | 10 | 11 | // if (data.username !== "zain") { 12 | // setError("form", {message:"Your crendentials are invalid"}) 13 | // }if(data.username === "rahat"){ 14 | // setError("blocked", {message:"sorry this user is blocked"}) 15 | // */ 16 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Connecting-React-to-Express-Backend 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /backend/server.js: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import bodyParser from "body-parser"; 3 | import cors from "cors"; 4 | 5 | const app = express(); 6 | const port = 3000; 7 | 8 | app.use(bodyParser.json()); 9 | app.use(cors()); 10 | 11 | app.get('/', (req, res) => { 12 | res.send('Hello World!'); 13 | }); 14 | 15 | app.post('/', (req, res) => { 16 | console.log(req.body); 17 | res.json({ message: 'Hello World!', username: req.body.username }); 18 | }); 19 | 20 | app.listen(port, () => { 21 | console.log(`Example app listening on port ${port}`); 22 | }); 23 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | body{ 5 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 6 | line-height: 1.5; 7 | font-weight: 400; 8 | 9 | color-scheme: light dark; 10 | color: rgba(255, 255, 255, 0.87); 11 | background-color: #242424; 12 | 13 | font-synthesis: none; 14 | text-rendering: optimizeLegibility; 15 | -webkit-font-smoothing: antialiased; 16 | -moz-osx-font-smoothing: grayscale; 17 | } 18 | .red{ 19 | color: red; 20 | font-size: 12px; 21 | text-align: start; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:react/recommended', 7 | 'plugin:react/jsx-runtime', 8 | 'plugin:react-hooks/recommended', 9 | ], 10 | ignorePatterns: ['dist', '.eslintrc.cjs'], 11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 12 | settings: { react: { version: '18.2' } }, 13 | plugins: ['react-refresh'], 14 | rules: { 15 | 'react/jsx-no-target-blank': 'off', 16 | 'react-refresh/only-export-components': [ 17 | 'warn', 18 | { allowConstantExport: true }, 19 | ], 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "connecting-react-to-express-backend", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "body-parser": "^1.20.2", 14 | "cors": "^2.8.5", 15 | "express": "^4.19.2", 16 | "react": "^18.2.0", 17 | "react-dom": "^18.2.0", 18 | "react-hook-form": "^7.51.5" 19 | }, 20 | "devDependencies": { 21 | "@types/react": "^18.2.66", 22 | "@types/react-dom": "^18.2.22", 23 | "@vitejs/plugin-react": "^4.2.1", 24 | "autoprefixer": "^10.4.19", 25 | "eslint": "^8.57.0", 26 | "eslint-plugin-react": "^7.34.1", 27 | "eslint-plugin-react-hooks": "^4.6.0", 28 | "eslint-plugin-react-refresh": "^0.4.6", 29 | "postcss": "^8.4.38", 30 | "tailwindcss": "^3.4.4", 31 | "vite": "^5.2.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.github/workflows/static.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy static content to Pages 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["main"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 19 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 20 | concurrency: 21 | group: "pages" 22 | cancel-in-progress: false 23 | 24 | jobs: 25 | # Single deploy job since we're just deploying 26 | deploy: 27 | environment: 28 | name: github-pages 29 | url: ${{ steps.deployment.outputs.page_url }} 30 | runs-on: ubuntu-latest 31 | steps: 32 | - name: Checkout 33 | uses: actions/checkout@v4 34 | - name: Setup Pages 35 | uses: actions/configure-pages@v5 36 | - name: Upload artifact 37 | uses: actions/upload-pages-artifact@v3 38 | with: 39 | # Upload entire repository 40 | path: '.' 41 | - name: Deploy to GitHub Pages 42 | id: deployment 43 | uses: actions/deploy-pages@v4 44 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import { useForm } from 'react-hook-form'; 3 | import './App.css'; 4 | 5 | function App() { 6 | const [isDataSaved, setIsDataSaved] = useState(false); 7 | const { 8 | register, 9 | handleSubmit, 10 | setError, 11 | reset, 12 | formState: { errors, isSubmitting } 13 | } = useForm(); 14 | 15 | const delay = (d) => { 16 | return new Promise((resolve) => { 17 | setTimeout(() => { 18 | resolve(); 19 | }, d * 1000); 20 | }); 21 | } 22 | 23 | const onSubmit = async (data) => { 24 | await delay(2); 25 | 26 | try { 27 | const response = await fetch('http://localhost:3000/', { 28 | method: 'POST', 29 | headers: { 30 | 'Content-Type': 'application/json', 31 | }, 32 | body: JSON.stringify(data), 33 | }); 34 | 35 | if (!response.ok) { 36 | throw new Error('Network response was not ok'); 37 | } 38 | 39 | const result = await response.json(); 40 | console.log(result); 41 | 42 | setIsDataSaved(true); 43 | reset(); 44 | 45 | } catch (error) { 46 | console.error('Error:', error); 47 | } 48 | }; 49 | 50 | return ( 51 |
52 |
53 | {isSubmitting &&
loading...
} 54 | {isDataSaved &&
Your data is saved
} 55 |
56 |
57 | 71 |
72 |
73 | 87 |
88 | 93 | {errors.form &&
{errors.form.message}
} 94 | {errors.blocked &&
{errors.blocked.message}
} 95 |
96 |
97 |
98 | ); 99 | } 100 | 101 | export default App; 102 | -------------------------------------------------------------------------------- /src/assets/react.svg: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------