Javascript 如何在React.JS中更改登录/注销时的导航栏文本?

Javascript 如何在React.JS中更改登录/注销时的导航栏文本?,javascript,reactjs,react-router,react-hooks,Javascript,Reactjs,React Router,React Hooks,我的项目中有一个导航栏,我从App.js内部调用它。根据我是否登录,我希望呈现NavBar的不同视图。如果登录,我希望导航栏有一个注销按钮。如果注销,我希望导航栏上有登录按钮。我使用localStorage中的令牌检查我是否登录。登录时,令牌出现在localStorage中。注销时/登录前,localStorage中没有令牌密钥。我将此令牌作为状态传递给NavBar,如图所示: export default function App() { const [loggedIn, setLogg

我的项目中有一个导航栏,我从
App.js
内部调用它。根据我是否登录,我希望呈现
NavBar
的不同视图。如果登录,我希望
导航栏
有一个注销按钮。如果注销,我希望导航栏上有登录按钮。我使用
localStorage
中的令牌检查我是否登录。登录时,令牌出现在
localStorage
中。注销时/登录前,
localStorage
中没有令牌密钥。我将此令牌作为状态传递给
NavBar
,如图所示:

export default function App() {
   const [loggedIn, setLoggedIn] = useState(localStorage.getItem("token"));
   return (
      <div>
         <Router>
            <Navbar isAuth={loggedIn} />
            <Route exact path="/" exact component={Home} />
            <Route path="/login" component={Login} />
            <PrivateRoute path="/dashboard" component={Dashboard} />
         </Router>
      </div>
   );
} 
问题是,
NavBar
不会在我登录后立即更新自身。我必须手动刷新页面才能呈现新的
NavBar
。同样,在注销时,它也不更新自身,只在手动刷新时更新。问题是什么?如何解决

您还需要添加。从文件中:

渲染与该位置匹配的第一个子对象

的独特之处在于它以独占方式呈现路由。相反,每个与位置匹配的
都以包含方式呈现

如下所示:

<Router>
  <Switch>
     <Navbar isAuth={loggedIn} />
     <Route exact path="/" exact component={Home} />
     <Route path="/login" component={Login} />
     <PrivateRoute path="/dashboard" component={Dashboard} />
  </Switch>
</Router>

请在此进一步阅读:


我希望这有帮助

如果更改localStorage中
标记的值,则应用程序的状态不会更新

您需要确保更新状态,如果有帮助,我已经添加了一个。我找到了一个简单的解决方案: 使用componentDidMount()或useEffect()函数,该函数将在加载导航栏页面时自动呈现。 在该函数中,使用setInterval()函数连续检索身份验证状态(例如,间隔为5000)。这将持续刷新导航栏,并立即更改按钮。 我想您必须将auth检查放在NavBar组件本身中,而不是使用道具。我把我想更改的特定按钮放在一个名为NavBarUser的单独组件中,该组件将“login | signup”更改为“logout”,并包含一个用户化身。然后,我将该组件插入导航栏本身的适当位置。 这就是我的代码的样子: ``` 从“React”导入React,{useState,useffect}; 从“./Avatar”导入化身; 从“react Router dom”导入{BrowserRouter as Router,Link}

const NavBarUser = () => {

    const [user, setUser] = useState({});
    useEffect(() => {
    { /*
        setInterval was used in order to refresh the page constantly
    in order to have the "logout" button show immediately in place of
    "login", as soon as user logs out.
    */}
        setInterval(() => {
            const userString = localStorage.getItem("user");
            const user = JSON.parse(userString);
            setUser(user);
            }, [])
    }, 5000);


    const logout = () => {
        return localStorage.removeItem("user");
    }

    if (!user) {
        return (
            <div className="navbar-nav ml-auto">
                <Link to="/login" className="nav-item nav-link">Login</Link> <span 
className="nav-item nav-link">|</span> <Link to="/SignUp" className="nav-item nav- 
link">Sign Up</Link>
            </div>
        )
    }
    if (user) {
       return (
         <div className="navbar-nav ml-auto">
            <Link to="/" className="nav-item nav-link" onClick={logout}>Logout</Link>
                    <Avatar img="/images/Eat-healthy.jpg" />
            </div>
        )
    }


}


export default NavBarUser;

```
const NavBarUser=()=>{
const[user,setUser]=useState({});
useffect(()=>{
{ /*
setInterval用于不断刷新页面
为了让“注销”按钮立即显示在
“登录”,一旦用户注销。
*/}
设置间隔(()=>{
const userString=localStorage.getItem(“用户”);
const user=JSON.parse(userString);
setUser(用户);
}, [])
}, 5000);
常量注销=()=>{
返回localStorage.removietem(“用户”);
}
如果(!用户){
返回(
登录|注册
)
}
如果(用户){
返回(
注销
)
}
}
导出默认NavBarUser;
```

以下是我解决此问题的方法:

首先,我在我的
App
类中创建了一个
isLoggedIn
状态。我给了它一个
componentDidMount()
方法,该方法将在应用程序启动时从cookie获取登录状态。然后我创建了
globalgoin
globalgout
方法作为箭头函数,它们相应地将
isLoggedIn
状态设置为true或false。我将
Nav
组件
isLoggedIn
状态作为道具传递,并传递
Login
Nav
路由
globalLogin
globalout
方法。然后,可以使用
this.props.globallout()从
Login
Nav
调用这些方法
this.props.globalwin()

这是我的
App.js
的简化版本

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      isLoggedIn: false,
    }
  }
  componentDidMount() {
    const token = Cookie.get("token") ? Cookie.get("token") : null;
    if (token) {
      this.setState({ "isLoggedIn": true });
    }
  }
  globalLogin = () => {
    this.setState({ "isLoggedIn": true });
  }
  globalLogout = () => {
    this.setState({ "isLoggedIn": false });
  }

  render() {
    return (
      <Router>
        <div className="App">
          <Nav isLoggedIn={this.state.isLoggedIn} globalLogout={this.globalLogout}/>
          <Switch>
            <Route path="/" exact component={Home} />
            <Route path="/login" exact>
              <Login globalLogin={this.globalLogin}/>
            </Route>
          </Switch>
        </div>
      </Router>
    );
  }
}
类应用程序扩展组件{
建造师(道具){
超级(道具);
此.state={
伊斯洛格丁:错,
}
}
componentDidMount(){
const token=Cookie.get(“token”)?Cookie.get(“token”):null;
如果(令牌){
this.setState({“isLoggedIn”:true});
}
}
珠蛋白=()=>{
this.setState({“isLoggedIn”:true});
}
GlobalOut=()=>{
this.setState({“isLoggedIn”:false});
}
render(){
返回(
);
}
}
编辑:在上面的登录模块中使用history.push不起作用,所以我添加了一个中介来处理道具

render() {
    const LoginIntermediate = (props) => {
      return (
        <Login {...props} globalLogin={this.globalLogin}/>
      )
    }
    return (
      <Router>
        <div className="App">
          <Nav isLoggedIn={this.state.isLoggedIn} globalLogout={this.globalLogout}/>
          <Switch>
            <Route path="/" exact component={Home} />
            <Route path="/login" exact component={LoginIntermediate} />
          </Switch>
        </div>
      </Router>
    );
  }
render(){
const LoginIntermediate=(道具)=>{
返回(
)
}
返回(
);
}

使用switch停止呈现我的其他组件,如Home,在点击它们的URL时登录。我认为问题在于应用程序和导航栏之间的状态传递。按钮在导航栏内部,而不是在代码演示的外部。然后,您需要从父级发送一个函数作为道具,单击按钮时您将调用该函数。这样可以控制父类中的状态。看,这应该会有帮助。
render() {
    const LoginIntermediate = (props) => {
      return (
        <Login {...props} globalLogin={this.globalLogin}/>
      )
    }
    return (
      <Router>
        <div className="App">
          <Nav isLoggedIn={this.state.isLoggedIn} globalLogout={this.globalLogout}/>
          <Switch>
            <Route path="/" exact component={Home} />
            <Route path="/login" exact component={LoginIntermediate} />
          </Switch>
        </div>
      </Router>
    );
  }