简体   繁体   English

登录到其他组件后响应发送状态以更改 html

[英]React send state after login to other component to change html

I'm working on a project ( symfony API ) and ReactJs front-end,我正在做一个项目(symfony API)和 ReactJs 前端,

I have a login page which is connected to the api when i get the 201 http response i redirect the user to '/' and set the token in the localstorage but i have an issue in my navbar i have 2 buttons 1 login and the other is for register to redirect to both pages.我有一个登录页面,当我收到 201 http 响应时连接到 api 我将用户重定向到“/”并在 localstorage 中设置令牌但我的导航栏中有问题我有 2 个按钮 1 个登录和另一个用于注册重定向到两个页面。

When i log in i want to dynamically change the header to a dropdown with user informations and links to user settings etc ... Do you have any ideas ?当我登录时,我想将标题动态更改为包含用户信息和用户设置链接等的下拉列表......你有什么想法吗?

Here is the code of Navbar component :这是导航栏组件的代码:

    import React, {useEffect, useState} from 'react';
import Dropdown from "./Dropdown";
import {Link} from "react-router-dom";


const Navbar = () => {
    const [isloggedin, setIsloggedin] = useState(false);

    useEffect(() => {
        if (!localStorage.getItem('auth')) {
            setIsloggedin(false);
        } else {
            setIsloggedin(true);
        }

    }, [])

    const ToggleMobileMenu = () => {
        const mobile_menu = document.getElementById('mobile-menu')
        if (mobile_menu.classList.contains('mobile-hidden')){
            mobile_menu.classList.remove('mobile-hidden')
        } else {
            mobile_menu.classList.add('mobile-hidden')
        }
    }

    return (
        <nav className="bg-gray-800 w-full p-4">
            <div className="max-w-7xl mx-auto px-2 sm:px-6 lg:px-8">
                <div className="relative flex items-center justify-between h-16">
                    <div className="absolute inset-y-0 left-0 flex items-center sm:hidden">
                        <button type="button"
                                className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
                                aria-controls="mobile-menu" aria-expanded="false"
                                onClick={ToggleMobileMenu}
                        >
                            <span className="sr-only">Open main menu</span>
                            <svg className="block h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none"
                                 viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2"
                                      d="M4 6h16M4 12h16M4 18h16"/>
                            </svg>
                            <svg className="hidden h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none"
                                 viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
                                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2"
                                      d="M6 18L18 6M6 6l12 12"/>
                            </svg>
                        </button>
                    </div>
                    <div className="flex-1 flex items-center justify-center sm:items-stretch sm:justify-start">
                        <div className="flex-shrink-0 flex items-center">
                            <Link to={'/'}><img src={'./assets/logo.png'} width={'150'} alt={''}/></Link>
                        </div>
                        <div className="hidden sm:flex items-center sm:ml-6 flex">
                            <div className="flex space-x-4 items-center">
                                <Link to={'/'}
                                      className="bg-gray-900 text-white px-3 py-2 rounded-md text-sm font-medium"
                                      aria-current="page">Accueil</Link>

                                <Link to={'/products'}
                                      className="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Nos
                                    Produits
                                </Link>

                                <Link to={'/delivery'}
                                      className="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Livraison</Link>

                                <Link to={'/contact'}
                                      className="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Contact</Link>
                            </div>
                        </div>
                    </div>
                    <div
                        className="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
                        <div className={'ml-3 relative'}>
                            {isloggedin ? (
                                <div className={'ml-3 relative'}>
                                    <Dropdown/>
                                </div>
                            ) : (
                                <div className={'ml-3 relative flex'}>
                                    <Link to={'/login'}
                                          className={'hidden md:flex mr-5 text-white bg-red-200 p-3 rounded'}>Se
                                        connecter</Link>
                                    <Link to={'/register'}
                                          className={'hidden md:flex mr-5 text-white bg-red-200 p-3 rounded'}>S'inscrire</Link>
                                </div>

                            )}

                        </div>
                    </div>
                </div>
            </div>
            <div className="sm:hidden mobile-hidden" id="mobile-menu">
                    <div className="px-2 pt-2 pb-3 space-y-1">
                        <Link to={'/'}
                              className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Accueil</Link>
                        <Link to={'/products'}
                              className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Nos Produits</Link>
                        <Link to={'/delivery'}
                              className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Livraison</Link>
                        <Link to={'/contact'}
                              className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Contact</Link>
                        {isloggedin ? (
                            <Link to={'/account'}
                                  className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Mon compte</Link>
                        ) : (
                            <div>
                            <Link to={'/login'}
                                  className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Login</Link>
                                <Link to={'/register'}
                                      className="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium mobile-link" onClick={ToggleMobileMenu}>Register</Link>
                            </div>

                        )}


                    </div>
            </div>
        </nav>
    )
}
export default Navbar;

And here is the Login component :这是登录组件:

import React, {useState} from "react";
import { useHistory } from 'react-router-dom';
import axios from "axios";

const Login = () => {
    let history = useHistory()
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
    const [error, setError] = useState('');
    const [success, setSuccess] = useState('');


    const LoginHandler = () => {
        axios.post('http://127.0.0.1:8000/api/login', {
            'username': username,
            'password': password
        })
            .then((r) => {
                console.log(r)
                setError('')
                setSuccess('Vous etes connecté')
                setTimeout(() => {
                    localStorage.setItem('auth', r.data.token)
                    history.push('/', {auth: true})
                }, 3000)
            }).catch((error) => {
                setError("Username ou mot de passe éroné");
        })
    }

    return (
        <div>
            <div className={'text-center font-semibold mt-2'}>
                {error ? (<p className={'text-red-500'}>{error}</p>) : ( '' )}
                {success ? (<p className={'text-green-500'}>{success}</p>) : ( '' )}
            </div>
            <div className="divide-y divide-gray-200">
                <div className="py-8 text-base leading-6 space-y-4 text-gray-700 sm:text-lg sm:leading-7">
                    <div className="relative">
                        <input autoComplete="off" id="username" name="username" type="text"
                               className="peer placeholder-transparent h-10 w-full border-b-2 border-gray-300 text-gray-900 focus:outline-none focus:borer-rose-600"
                               placeholder="Username"
                               onChange={(e) => setUsername(e.target.value)}
                        />
                        <label htmlFor="username"
                               className="absolute left-0 -top-3.5 text-gray-600 text-sm peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-440 peer-placeholder-shown:top-2 transition-all peer-focus:-top-3.5 peer-focus:text-gray-600 peer-focus:text-sm">username</label>
                    </div>
                    <div className="relative">
                        <input autoComplete="off" id="password" name="password" type="password"
                               className="peer placeholder-transparent h-10 w-full border-b-2 border-gray-300 text-gray-900 focus:outline-none focus:borer-rose-600"
                               placeholder="Password"
                               onChange={(e) => setPassword(e.target.value)}
                        />
                        <label htmlFor="password"
                               className="absolute left-0 -top-3.5 text-gray-600 text-sm peer-placeholder-shown:text-base peer-placeholder-shown:text-gray-440 peer-placeholder-shown:top-2 transition-all peer-focus:-top-3.5 peer-focus:text-gray-600 peer-focus:text-sm">Password</label>
                    </div>
                    <div className="flex justify-center pt-6">
                        <button onClick={LoginHandler} className="bg-blue-500 text-white rounded-md px-2 py-1">Se
                            connecter
                        </button>
                    </div>
                </div>
            </div>
        </div>
    )

}

export default Login;

Right now your useEffect hook:现在你的 useEffect 钩子:

useEffect(() => {
    if (!localStorage.getItem('auth')) {
        setIsloggedin(false);
    } else {
        setIsloggedin(true);
    }

}, [])

... is only triggered on the initial render of the navbar. ...仅在导航栏的初始渲染时触发。

You have two options - I'd strongly advice to use the second one.您有两个选择——我强烈建议使用第二个。


Option 1: The useEffect Hook has a dependency list (the second parameter passed to useEffect . Whenever any value inside that dependency list changes, the code is run again. So in order for the navbar to update, you have to add that localStorage "state" to the list. However, I don't know whether this will work that well - this is not the "react way" of doing things.选项 1: useEffect Hook 有一个依赖项列表(传递给useEffect的第二个参数。只要该依赖项列表中的任何值发生更改,代码就会再次运行。因此,为了更新导航栏,您必须添加该 localStorage “状态”到列表中。但是,我不知道这是否会奏效——这不是做事的“反应方式”。


Option 2: Change your State Hierarchy.选项 2:更改您的状态层次结构。 Right now your hierarchy looks like this:现在您的层次结构如下所示:

<Navbar>
    <Login>
</Navbar>

In react you should store state with useState (you can add auth to the localStorage in addition to that).在反应中,您应该使用 useState 存储状态(除此之外,您还可以向 localStorage 添加auth )。 That state should be stored in the highest order component that is affected by the state.该状态应存储在受该状态影响的最高阶组件中。

Solution: useState for a user object inside Navbar.解决方案:对导航栏中的用户对象使用状态。 Pass the setUserState function to the login component and trigger setUserState on successful login (next to localStorage.setItem).将 setUserState 函数传递给登录组件并在成功登录时触发 setUserState(在 localStorage.setItem 旁边)。 Add that userState to the dependency list of the useEffect hook mentioned above.将该 userState 添加到上述 useEffect 挂钩的依赖项列表中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM