reactjs - 登录到其他组件后响应发送状态以更改 html
问题描述
我正在开发一个项目( symfony API )和 ReactJs 前端,
我有一个登录页面,当我收到 201 http 响应时连接到 api 我将用户重定向到“/”并在本地存储中设置令牌,但我的导航栏中有问题我有 2 个按钮 1 个登录和另一个用于注册重定向到两个页面。
当我登录时,我想将标题动态更改为包含用户信息和用户设置链接等的下拉列表......你有什么想法吗?
这是导航栏组件的代码:
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;
这是登录组件:
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;
解决方案
现在你的 useEffect 钩子:
useEffect(() => {
if (!localStorage.getItem('auth')) {
setIsloggedin(false);
} else {
setIsloggedin(true);
}
}, [])
...仅在导航栏的初始渲染时触发。
你有两个选择 - 我强烈建议使用第二个。
选项 1: useEffect Hook 有一个依赖列表(传递给 . 的第二个参数useEffect
。每当该依赖列表中的任何值发生更改时,代码都会再次运行。因此,为了更新导航栏,您必须添加该 localStorage “状态”但是,我不知道这是否会很好地工作 - 这不是做事的“反应方式”。
选项 2:更改您的状态层次结构。现在您的层次结构如下所示:
<Navbar>
<Login>
</Navbar>
在反应中,您应该使用 useState 存储状态(除此之外,您还可以添加auth
到 localStorage)。该状态应存储在受该状态影响的最高阶组件中。
解决方案:在导航栏中为用户对象使用状态。将 setUserState 函数传递给登录组件,并在成功登录时触发 setUserState(在 localStorage.setItem 旁边)。将该 userState 添加到上面提到的 useEffect 挂钩的依赖项列表中。
推荐阅读
- python - 外部网络方法的代理实现
- pyspark - 如何从火花数据框中获取单个值
- mysql - Nodejs,Express mysql总是返回ER_BAD_DB_ERROR
- android - 如何使用 Kotlin 在谷歌地图上添加标记?
- nginx - NGINX,从http标头中提取url路径
- python - 用于发送消息的公共 API(asyncore、Python)
- laravel - 波斯语本地化问题
- c# - 在 DataGridView 中单击单元格时填充组合框文本/值
- python - 所有预安装的 Python 包都自动包含在新的 Virtualenv 中
- replace - VS Code 使用正则表达式查找和替换包含新行的文本