React Router: как сохранить данные в журнале (реквизиты) при перенаправлении - PullRequest
0 голосов
/ 25 ноября 2018

Я создаю приложение React Router и изучаю аутентификацию.Вот некоторые части:

Компонент входа (login.jsx)

  • проверяет подлинность учетных данных пользователя на серверной части
  • устанавливает токен аутентификации в локальном хранилище
  • возвращает данные пользователя
  • устанавливает состояние с данными
  • передает состояние компоненту администратора

компонент администратора (admin.jsx)

  • защищен частным маршрутом (см. Privateroute.jsx)
  • в основном компонент контейнера
  • передает данные пользователя и отображает другие компоненты, которые отображают / редактируют данные

Кнопка аутентификации на навигационной панели (authbutton.jsx)

  • проверяет, вошел ли пользователь в систему, и отображает кнопку «вход» или «выход»
  • , если вошел в систему,также отображает кнопку «Мои сообщения», которая перенаправляет к администратору

Все хорошо работает от входа к администратору.Моя проблема в том, что, когда я щелкаю на странице администратора (например, на домашней странице), а затем нажимаю кнопку «Мои сообщения», он перенаправляется на страницу «Администратор» и знает, что я вошел в систему, но данные пользователя больше недоступны.Раньше, исходя из компонента входа в систему, данные пользователя были в 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 }

кнопка авторизации.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 ]

0 голосов
/ 28 ноября 2018

Кажется, есть два основных решения моей проблемы.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) ...
0 голосов
/ 25 ноября 2018

Это одна из причин создания магазинов.Думайте о нем как о глобальном объекте, к которому можно получить доступ из любого места в вашем приложении.

Я лично использовал mobx / mobx-реаги * (легко и магически), а также redux

Используя mobx, вы можете сделать что-то вроде этого:

Глобальное хранилище

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

Root App Component

// /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>
       )
    }
}
...