Hur lägga upp i ReactJS? (MERN-stack)

Permalänk

Hur lägga upp i ReactJS? (MERN-stack)

Tjo! Äntligen har jag kommit igång med ReactJS-delen i MERN-projektet i kursen efter säkert 5000 koder bara i REST API:t - troligen helt i onödan gällande betyg. Det jag funderar nu på är lite det här med att lägga upp med `prop drilling`, useStates å useEffects i ReactJS.

Jag fick nämligen lära mig den jobbiga vägen att det här med att försöka markera DOM-element direkt (se hamburgermenyn i Header.js) är inte rekommenderat då inga DOM-element finns renderade när du väl försöker "markera" dem direkt med getElementById! 🤦‍♂️

Tanken är att `Header.js` ska endast visa navigering efter inloggning och du får endast se "Admin"-knappen om du är inloggad + "sysadmin". Detta fungerar just nu i Header.js-komponenten (när jag använder "DevTools Panel" för React å bara automatiskt slår på states) men den är ju beroende av att jag lyckas logga in från en undersida vilket jag antar det är `react-router-dom` som gäller för undersidor likt "<Router-link>" från VueJS? Eller någon skillnad här mellan ReactJS å VueJS gällande undersidor?

Följande har jag just nu (obs: endast JS, kan ej TS, blir vid annat tillfälle) i ReactJS-klienten:

index.js

import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; // Jaså du React, DU får markera ett element i DOM men jag måste använda mig av states överallt?! (se hamburgermenyn i Header.js) const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <React.StrictMode> <App /> </React.StrictMode> );

Dold text

App.js

import "./App.css"; import Header from "./components/Header"; import Footer from "./components/Footer"; function App() { return ( <div className="mx-auto"> <Header /> <main className="mx-auto max-w-screen-xl p-4">Placera router här</main> <Footer /> </div> ); } export default App;

Dold text

Header.js

import "../App.css"; import { useState, useEffect } from "react"; function Header() { // Some initial state that are false because we use fetch() to know what access we have const [isLoggedIn, setIsLoggedIn] = useState(false); const [isAdmin, setIsAdmin] = useState(false); const [showMobileMenu, setShowMobileMenu] = useState(false); // useEffect for handling hamburger menu useEffect(() => { // We should NOT use direct DOM Manip so instead we listen for click and just match const handleClick = (e) => { if (e.target.matches("a") && showMobileMenu) { setShowMobileMenu(false); } }; // When we click outside of the menu and it is TRUE that menu is showing const handleOutsideClick = (e) => { if (showMobileMenu && !e.target.matches("#mobile-menu-button")) { setShowMobileMenu(false); } }; // Start listening again for new clicks document.addEventListener("click", handleClick); document.addEventListener("click", handleOutsideClick); // Remove listeners when component is removed/unmounted return () => { document.removeEventListener("click", handleClick); document.removeEventListener("click", handleOutsideClick); }; }, [showMobileMenu]); // Run this useEffect any time this value changes! return ( <header className="bg-gray-800 p-4 d-flex justify-between items-center sticky w-full top-0 z-50"> <nav className="mx-auto flex items-center justify-between"> <a className="text-white text-sm lg:text-2xl font-bold ml-6 hover:text-cyan-500" href="/"> AI DATORER AB Intranät </a> {isLoggedIn && ( <ul className={`md:flex space-x-4 p-2 mr-4 ${ isLoggedIn ? "flex" : "hidden" }`}> <li className="text-white cursor-pointer hover:underline font-bold"> Start </li> {isAdmin && ( <li className="text-white cursor-pointer hover:underline font-bold"> Admin </li> )} <li className="text-white cursor-pointer hover:underline font-bold"> Produkter </li> <li> <button className="text-white cursor-pointer hover:underline font-bold"> Logga ut </button> </li> </ul> )} {isLoggedIn && ( <div className={`md:hidden mr-2`}> <button onClick={() => setShowMobileMenu((prev) => !prev)} id="mobile-menu-button" className="text-white p-2 focus:outline-none"> <span className="block w-7 h-1 bg-white mb-1"></span> <span className="block w-7 h-1 bg-white mb-1"></span> <span className="block w-7 h-1 bg-white"></span> </button> {showMobileMenu && ( <ul className={`${ showMobileMenu ? "block" : "hidden" } absolute top-14 right-1 mt-2 bg-white text-gray-800 border rounded-md`} id="mobile-menu"> <li className="block px-4 py-2 cursor-pointer hover:underline hover:bg-blue-100 font-bold"> Start </li> {isAdmin && ( <li className="block px-4 py-2 cursor-pointer hover:underline hover:bg-blue-100 font-bold"> Admin </li> )} <li className="block px-4 py-2 cursor-pointer hover:underline hover:bg-blue-100 font-bold"> Produkter </li> <li> <button className="block px-4 py-2 cursor-pointer hover:underline hover:bg-blue-100 font-bold"> Logga ut </button> </li> </ul> )} </div> )} </nav> </header> ); } export default Header;

Dold text

Footer.js

import "../App.css"; function Footer() { return ( <footer className="bg-gray-800 p-4 text-white"> <p className="text-m font-bold text-center mx-4 my-2"> OBS: Alla bilder är lånade från webben enbart i skolsyfte och raderas efter betygsatt projektuppgift! </p> <p className="text-sm text-center font-bold mx-4 my-4"> &copy;2023 WebbKodsLärlingen | AI DATORER AB | Projektuppgift HT2023 DT162G </p> </footer> ); } export default Footer;

Dold text

Min huvudsakliga fråga är var jag bör lägga mina states kring att man är inloggad (isLoggedIn) för den kommer att vara avgörande för att veta vilka undersidor man ska ha åtkomst till.

Jag ska även ha en till state som ska laddas vid lyckad inloggning: en array med Roles/Accesses vilket ger booleans om vad som sedan ska visas utifrån åtkomst (allt kontrolleras också på REST API-sidan så CRUD kontrolleras dubbelt). Men nu gäller det alltså vad som ska visas i UI-klienten via ReactJS.

Eller kan jag köra med en "fuling" där barnelementen skickar upp tillbaka till föräldrarna att nu har vi lyckats logga in så nu kan du ändra boolean för "isLoggedIn" så att navigeringen visas?

Tack så hemskt mycket på svar på förhand!

Mvh,
WKL.

Visa signatur

"Den säkraste koden är den som aldrig skrivs"

Permalänk
Medlem

Nu är jag ingen expert på React och det finns nog många sätt men du kan ha isLoggedIn i app och med hjälp av den styra med routern vad man har åtkomst till.

Är man inte inloggad så <Navigate to="login" /> annars rendera önskad sida/komponent.

Permalänk
Medlem

Användarinfo känns ju som ett typiskt användningsområde för useContext-hooken för att slippa prop drilling.
Du wrappar dina komponenter som behöver informationen med din context.

https://react.dev/reference/react/useContext