当前位置: 首页 > 知识库问答 >
问题:

React Router:如何在重新路由时保留已登录数据(道具)

公羊英达
2023-03-14

我正在创建一个React Router应用程序,并且正在学习身份验证。以下是部分内容:

登录组件(Login.jsx)

  • 在后端验证用户的凭据
  • 在本地存储中设置身份验证令牌
  • 返回用户的数据
  • 数据设置状态
  • 将状态传递给管理组件

管理组件(Admin.jsx)

  • 受专用路由保护(请参阅privateroute.jsx)
  • 基本上是容器组件
  • 将用户的数据传递给并呈现显示/编辑数据的其他组件

导航栏上的Authentication按钮(authButton.jsx)

  • 检查用户是否已登录并显示“登录”或“注销”按钮
  • 如果已登录,则还会呈现“我的帖子”按钮,该按钮路由到管理员

从登录到管理都很好。我的问题是,当我单击管理员页面(如主页),然后单击“我的帖子”按钮时,它会重新路由到管理员,并知道我已登录,但用户的数据不再可用。之前,来自login组件的用户数据位于this.props.location.state.me中。

我被卡住了,因为我正试图从两个不同的组件路由到Admin,而我以前从来没有这样做过。此外,我觉得在身份验证设置中有一个解决方案是我所缺少的。

其他想法:

当传递用户的数据时,我是否应该在Admin中有条件地设置状态?

我是否应该像使用身份验证令牌一样将数据存储在浏览器的本地存储中?

我尝试获取数据,在Admin中使用ComponentDidMount设置状态,但它没有重新呈现,所以我读到使用ComponentWillReceiveProps,但这已被弃用,并被GetDerivedStateFromProps取代。我想不出来。

login.jsx

import React, { Component, Fragment } from 'react';
import * as userService from '../../services/user';
import { Redirect } from 'react-router-dom';
import IndeterminateProgress from '../utilities/indeterminateprogress';
import Nav from '../home/nav';

class Login extends Component {
    constructor(props) {
        super(props);
        this.state = {
            redirectToReferrer: false,
            email: '',
            password: '',
            feedbackMessage: '',
            checkingLogin: true,
            me: ''
        };
    }

    componentDidMount() {
        userService.checkLogin()
            .then((loggedIn) => {
                if (loggedIn) {
                    this.setState({ redirectToReferrer: true, checkingLogin: false });
                } else {
                    this.setState({ checkingLogin: false });
                }
            });
    }

    login(e) {
        e.preventDefault();
        userService.login(this.state.email, this.state.password)
            .then((meData) => {
                this.setState({ redirectToReferrer: true, me: meData })
            })  
            .catch((err) => {
                if (err.message) {
                    this.setState({ feedbackMessage: err.message });
                }
            });
    }

    handleEmailChange(value) {
        this.setState({ email: value });
    }

    handlePasswordChange(value) {
        this.setState({ password: value });
    }

    render() {
        const { from } = this.props.location.state || { from: { pathname: '/admin', state: { ...this.state } } };
        const { redirectToReferrer, checkingLogin } = this.state;

        if (checkingLogin) {
            return <IndeterminateProgress message="Checking Login Status..." />;
        }
        if (redirectToReferrer) {
            return (
                <Redirect to={from} />
            );
        }

        return (
            <Fragment>
                <Nav />
                <h2 className="heading center">Login to continue</h2>
                <form className="center" onSubmit={(e) => this.login(e)}>
                    <div className="form-group">
                        <input
                            placeholder="Email"
                            id="email"
                            className="col-3"
                            type="email"
                            onChange={(e) => this.handleEmailChange(e.target.value)}
                            required
                        />
                    </div>
                    <div className="form-group">
                        <input
                            placeholder="Password"
                            id="password"
                            className="col-3"
                            type="password"
                            onChange={(e) => this.handlePasswordChange(e.target.value)}
                            required
                        />
                    </div>
                    {this.state.feedbackMessage ? (
                        <p>{this.state.feedbackMessage}</p>
                    ) : null}
                    <input type="submit" value="Login" className="btn btn-info btn-sm" />
                </form>
            </Fragment>
        );
    }
}

export { Login };

Admin.jsx

import React, { Component } from 'react';
import Nav from '../home/nav';
import AdminBlogContainer from './adminblogcontainer'
import { BrowserRouter as Router, Link } from 'react-router-dom';

const Admin = (props) => {
    return (
        <div className="flexcol center">
            <Nav />
            <h1 className="heading">Your Blog Posts</h1>
            <AdminBlogContainer {...props.location.state.me} />
            <Link to={{
                pathname: '/write',
                state: { ...props.location.state.me }
            }}
                className="btn btn-outline-secondary mt-4"
            >Create a New Blog Post</Link>
        </div>
    )
}

export { Admin };

privateroute.jsx

import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { isLoggedIn } from '../../services/user';

const PrivateRoute = (props) => {
    const Component = props.component;
    const propsToPass = Object.assign({}, props);
    delete propsToPass.component;

    return (
        <Route {...propsToPass} render={props => (
            isLoggedIn() ? (
                <Component {...props} />
            ) : (
                <Redirect to={{
                    pathname: '/login',
                    state: { from: props.location }
                }} />
            )
        )} />
    );
};

export { PrivateRoute }

authButton.jsx

import React from 'react';
import { Link } from 'react-router-dom';
import { isLoggedIn } from '../../services/user';

const AuthButton = (props) => {
    if (isLoggedIn()) {
        return (
            <div>
                <Link className="btn btn-info m-1" to="/logout">Logout</Link>
                <Link className='btn btn-info m-1' to={{
                    pathname: '/admin',
                    // state: { ...this.state }
                }}
                    >My Posts</Link>
            </div>
        );
    } else {
        return (
            <div>
                <Link className="btn btn-info m-1" to="/login">Login</Link>
                <Link className="btn btn-info m-1" to="/register">Register</Link>
            </div>
        )
    }
};

export { AuthButton };

共有2个答案

邹海超
2023-03-14

我的问题似乎有两个主要的解决办法。%1是按此页上的答案使用存储。另一种是将数据存储在本地存储中,看起来是:

在login.jsx中设置本地存储而不是设置状态

login(e) {
        e.preventDefault();
        userService.login(this.state.email, this.state.password)
            .then((meData) => {
                localStorage.setItem("me", JSON.stringify(meData))
                this.setState({ redirectToReferrer: true})
            })  
            .catch((err) => {
                if (err.message) {
                    this.setState({ feedbackMessage: err.message });
                }
            });
    }

检索AdminBlogContainer.jsx中的数据

componentDidMount() {
    let meData = JSON.parse((localStorage.getItem("me")))
    authorsService.one(meData.id) ...
陈功
2023-03-14

这是创建商店的原因之一。将其视为一个全局对象,可以在应用程序中的任何地方访问。

我个人用过mobx/mobx-react(很容易,做事情很神奇),还有redux

使用mobx可以执行如下操作:

全局存储

// /stores/authentication.js
class AuthenticationStore {
   user = {};
   //authentication logic here
}
const authenticationStore = new AuthenticationStore();
export default authenticationStore;

根应用程序组件

// /app.js
import authenticationStore from './stores/authentication';
import { Provider } from 'mobx-react';

export default class App extends Component {

  render(){
   return (
   <Provider authenticationStore={authenticationStore}>
      <BrowserRouter>
         <SomeComponent/>
      </BrowserRouter>
   <Provider>);
   }

}

某些成分;

// /components/some.component.js
@inject('authenticationStore')
class SomeComponent extends Component {
    render(){
       const {authenticationStore} = this.props;
       const {user} = authenticationStore;
       render(
          <div>${user.name}</div>
       )
    }
}
 类似资料:
  • 问题内容: 我是AngularJS的新手,正在尝试为自己构建一个简单的小应用程序。我有正在使用抓取的应用程序的JSON数据,并且该数据在多个视图/路由之间应该相同。但是,当我转到新路线时,JSON数据(存储为)不再可用于新视图。我该怎么做才能将此数据传递到新视图,而无需再次获取?(本教程的电话目录应用程序每次都会根据我的判断重新获取此数据。) 据我了解,可以做到这一点,但似乎人们对此并不满意。如果

  • 问题内容: 我是新手。我正在使用获取对象列表并将其显示在第一页上的服务。然后根据单击的对象,在下一页上设置选项卡标题。但是,当我刷新页面时,列表的范围丢失了,并且选项卡头引发了异常,导致页面无法显示信息。即使刷新第二页,是否可以保留上一个屏幕上单击了哪个对象的信息? 问题答案: 您可以使用角度本地存储 角度本地存储 示例如何使用它: 使用本地存储的示例

  • 我想显示每个机组成员、基本信息以及他们合同中的最新开始日期。使用我的基本查询,它会为每个合同返回一行,复制具有不同开始和结束日期的基本信息。我只需要每个人一行,带有最新的开始日期(如果他们还没有开始日期,则为null)。 我对分组和分区函数的理解有限。我为类似日期逆向工程的查询使用分区并创建临时表进行选择。最终我可以重用它,但它似乎比我们需要的更复杂。 我只需要每列显示一行。前5列将始终相同。最后

  • 我现在一直在努力使用我的登录页面来让组件呈现Loggedin组件。我的前端是Reactjs,后端是NodeJS。我对nodejs、expression和react都是新手。 在loginform组件上,我使用fetch进行了一次post,它将用户名和密码传递给后端的相应endpoint。没问题。在后端,它读取我存储用户(不使用任何数据库)的jsonfile来查找匹配项,如果用户名和密码都匹配,则它

  • 问题内容: 我正在使用logback / slf4j处理我的应用程序中的日志记录。在我开始使用EJB之前,一切都运行良好。将无状态EJB添加到应用程序后,记录器开始忽略我的logback.xml,并停止使用附加程序。我切换到编程式记录器配置以查看出了什么问题,现在当我尝试在EJB中使用记录器时遇到以下错误: 源于这一行: 是否需要任何特殊的配置才能使Logback与EJB一起使用?如果有问题,我将

  • 我正在构建angular2应用程序,目前我有一个家庭组件与菜单栏和路由器出口的主要内容。我添加了登录机制,所以如果用户没有经过身份验证,那么登录页面将显示在整个屏幕上,登录后用户将被路由到上面结构的主/主组件。 当我运行登录页面加载的应用程序时,成功验证后,它会将我路由到主页,但在加载菜单的主页(如Dashboard1、Dashboard2、Report1等)中,链接无法正常工作。当我点击任何菜单