React state passing through children and passing back to parent

Viewed 48

I am sure there are similar questions and I have tried to research this but it was very confusing. I am creating a login page for a web application. I have a database that holds a username, password and a users position. A user will login and be sent to the page of their position. However I am using react-router-dom and I want to create a redirect if the users position isn't right however I can't seem to pass a state that is set in the login page

For my login page login.js, the username, password and the position are all states, the position is set when the server responds back with a truth statement and the users position. I then need to pass this back to my App.js which contains the router and routes, the position that was passed back from the login.js can now be used to authenticate that the user can go to that page.

App.js

// import { io } from "socket.io-client";
import Login from "./Components/Login"
import {BrowserRouter, Routes, Route} from "react-router-dom"
import Admin from "./Components/Admin"


function App() {
  // const socket = io("http://192.168.1.179:3001");

  // socket.on("connect", () => {
  //   console.log(socket.id);
  // });

  // socket.on("disconnect", () => {
  //   console.log(socket.id);
  // });

  return (
  <>
      <BrowserRouter>
        <Switch>
          <Routes>
            <Route path="/" element={<Login/>} />
            <Route path="/admin" element={<Admin />}/>
          </Routes>
        </Switch>
      </BrowserRouter>
    
  </>)
}

export default App;

Login.js

import React,{useState,useEffect, useRef} from 'react'
import {Button, Card, Form, FormLabel, Modal} from 'react-bootstrap'
import axios from "axios"
import Admin from './Admin'

export default function Login() {
    // User States
    const [username,setUsername] = useState("")
    const [password, setPassword] = useState("")
    const [position, setPosition] = useState("")

    // Modal State and Functions
    const [showModal, setShowModal] = useState(false);

    const handleCloseModal = () => setShowModal(false);
    const handleShowModal = () => setShowModal(true);

    const [message,setMessage] = useState("")

    //handleSubmit
    function submit(e){
        e.preventDefault()
        handleShowModal()
        login()
        handleCloseModal()
    }

    function incorrectUsername(){
        setMessage("Username Doesn't Exist!")
        setUsername("")
        setPassword("")
    }

    function incorrectPassword(){
        setMessage("Incorrect Password!")
        setPassword("")
    }

    function handleCorrectResponse(passedPosition){
        setMessage("Correct Username and Password")
        setPosition(passedPosition)
        
    }

    //handleLogin
    async function login(){
        await axios.get("http://0.0.0.0:3001/api/login", {params:{"username":username,
        "password":password}}).then((response)=>{
            if (response.data.key === 0){
                incorrectUsername()
            }
            else if(response.data.key === 1){
                incorrectPassword()
            }
            else if(response.data.key === 2){
                handleCorrectResponse(response.data.position)
            }
            else{
                setMessage("ERROR!")
            }
        })
    }

    // Page Rendering
    return (
        <div style={{
            display:"flex",
            justifyContent: "center",
            alignItems: "center",
            minHeight:"100vh"
            }}>
                {position}
            <Card style={{
                height:"450px",
                width:"400px",
                display:"flex",
                borderRadius:"10%"}}>
                <Card.Title style={{textAlign:"center",paddingTop:"15%"}}>
                    <h1>Login</h1>
                </Card.Title>
                <Card.Body >
                    <p style={{color:"red",textAlign:"center"}}>{message}</p>
                    <Form onSubmit={submit} >
                        <div style={{paddingBottom:"10%"}}>
                            <FormLabel>Username:</FormLabel>
                            <Form.Control onChange={(e)=>{
                                setUsername(e.target.value)
                            }} type="text" required value={username}/>
                        </div>
                        <div style={{paddingBottom:"10%"}}>
                            <FormLabel>Password:</FormLabel>
                            <Form.Control onChange={(e)=>{
                                setPassword(e.target.value)
                            }} type="password" required value={password}/>
                        </div>
                        <Button variant="primary" type="submit">Log In</Button>
                    </Form>
            
                    

                </Card.Body >
            </Card>

            {/* Modal */}
            <Modal
            backdrop = "static"
            keyboard = {false}
            show={showModal}
            onHide={handleCloseModal}
            aria-labelledby="contained-modal-title-vcenter"
            centered
            >
                <Modal.Title style={{padding:"5% 5%"}}>
                    Logging In...
                </Modal.Title>
            </Modal> 
        </div>
    
    )
}
1 Answers

Ok, passing data from Children to Parent and to another Children is not the approach you should be looking at.

Whenever you find yourself in this situation, don't store state in the Child, move the "state" up to store in parent, and you can pass that state to Child (login page) via props if the child need that data.

BUT

In this particular case, don't forget that React-router can store a "state" too (url + url param + or even a state)

In your case, it would make most sense to store "position" in react router state.

const history = useHistory();

function handleCorrectResponse(passedPosition){
        setMessage("Correct Username and Password")
        history.push({
          pathname: '/' // <--- url you want to go
          search: { /*... value(state) you want to show in url ... */},
          state: { /*...value(state) you don't want to show in url ...*/ }
        });
    }

And you can use useLocation, useParams to read those value.

read more here https://v5.reactrouter.com/web/api/history

Related