Данные не обновляются после входа на домашнюю страницу в reactjs

Я сохраняю пользовательские данные в localStorage в компоненте входа, а затем перенаправляю на домашнюю страницу. Имя пользователя на главной странице не обновляется при первом посещении. Я должен перезагрузить страницу. Затем данные привязываются к странице после обновления. Пожалуйста, помогите, как я могу показать данные о первом посещении?

ниже код моей домашней страницы

import React, { Component } from 'react';
import { Link } from 'react-router-dom';

export default class Header extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isLogin: false,
      isLogout: false,
      user: ""
    };
  }

  componentDidMount() {
    const userData = localStorage.getItem("userData");
    const user = JSON.parse(userData);
    this.setState({ user: user });
    if (userData) {
      this.setState({ isLogin: true });
    }
    console.info(userData);
    console.info(user);
  }

  logout = e => {
    e.preventDefault();
    localStorage.clear();
    this.setState({ isLogout: true });
  };

  render() {
    if (this.state.isLogin === false || this.state.isLogout === true) {
      return (
        <header
          id = "kr-header"
          className = "kr-header cd-auto-hide-header kr-haslayout"
        >
          <div className = "container">
            <div className = "row">
              <div className = "col-xs-12 col-sm-12 col-md-12 col-lg-12">
                <strong className = "kr-logo">
                  <Link to = "/">
                    <img src = "images/logo.png" alt = "company logo here" />
                  </Link>
                </strong>
                <nav className = "kr-addnav">
                  <ul>
                    <li>
                      <Link
                        id = "kr-btnsignin"
                        className = "kr-btn kr-btnblue"
                        to = "login_register"
                      >
                        <i className = "icon-smiling-face" />
                        <span>Join Now</span>
                      </Link>
                    </li>
                    <li>
                      <a
                        className = "kr-btn kr-btngreen"
                        href = "dashboardaddlisting.html"
                      >
                        <i className = "icon-plus" />
                        <span>Add Listing</span>
                      </a>
                    </li>
                  </ul>
                </nav>
                <nav id = "kr-nav" className = "kr-nav">
                  <div className = "navbar-header">
                    <button
                      type = "button"
                      className = "navbar-toggle collapsed"
                      data-toggle = "collapse"
                      data-target = "#kr-navigation"
                      aria-expanded = "false"
                    >
                      <span className = "sr-only">Toggle navigation</span>
                      <span className = "icon-bar" />
                      <span className = "icon-bar" />
                      <span className = "icon-bar" />
                    </button>
                  </div>
                  <div
                    id = "kr-navigation"
                    className = "collapse navbar-collapse kr-navigation"
                  >
                    <ul>
                      <li>
                        <a href = "dashboard.html">Dasboard</a>
                      </li>
                    </ul>
                  </div>
                </nav>
              </div>
            </div>
          </div>
        </header>
      );
    } else {
      return (
        <header
          id = "kr-header"
          className = "kr-header cd-auto-hide-header kr-haslayout"
        >
          <div className = "container">
            <div className = "row">
              <div className = "col-xs-12 col-sm-12 col-md-12 col-lg-12">
                <strong className = "kr-logo">
                  <Link to = "/">
                    <img src = "images/logo.png" alt = "company logo here" />
                  </Link>
                </strong>
                <nav className = "kr-addnav">
                  <ul>
                    <li>
                      <Link
                        id = "kr-btnsignin"
                        className = "kr-btn kr-btnblue"
                        to = "login_register"
                      >
                        <i className = "icon-smiling-face" />
                        <span>{this.state.user.user.firstname}</span>
                      </Link>
                    </li>
                    <li>
                      <a
                        className = "kr-btn kr-btngreen"
                        href = "dashboardaddlisting.html"
                      >
                        <i className = "icon-plus" />
                        <span>Add Listing</span>
                      </a>
                    </li>
                    <li>
                      <a onClick = {this.logout} className = "kr-btn kr-btngreen">
                        <i className = "icon-plus" />
                        <span>Logout</span>
                      </a>
                    </li>
                  </ul>
                </nav>
                <nav id = "kr-nav" className = "kr-nav">
                  <div className = "navbar-header">
                    <button
                      type = "button"
                      className = "navbar-toggle collapsed"
                      data-toggle = "collapse"
                      data-target = "#kr-navigation"
                      aria-expanded = "false"
                    >
                      <span className = "sr-only">Toggle navigation</span>
                      <span className = "icon-bar" />
                      <span className = "icon-bar" />
                      <span className = "icon-bar" />
                    </button>
                  </div>
                  <div
                    id = "kr-navigation"
                    className = "collapse navbar-collapse kr-navigation"
                  >
                    <ul>
                      <li>
                        <a href = "dashboard.html">Dasboard</a>
                      </li>
                    </ul>
                  </div>
                </nav>
              </div>
            </div>
          </div>
        </header>
      );
    }
  }
}

Ниже приведен код компонента входа-регистрации.

import React, {Component} from 'react';
import { Link,Redirect ,withRouter } from 'react-router-dom';
import PropTypes from "prop-types";
import Otp from './otp';
import axios from '../api';

export default class LoginRegister extends Component {
    static contextTypes = {
        router: PropTypes.object
      }
    constructor(props,context){
        super(props,context);
        this.state = {
            fname:'',
            lname:'',
            emailaddress:'',
            password:'',
            mobile:'',
            user:'',
            login_pass:'',
            isLogin:false
        }
        this.regi_data = this.regi_data.bind(this);
        this.login_data = this.login_data.bind(this);
        // this.otpModalRef = React.createRef();
    }

    regi_data(e){
        this.setState({[e.target.name] : e.target.value}
        );
    }
    login_data(e){
        this.setState({[e.target.name] : e.target.value})
    }

    // otpModalRef = ({onOpenModal}) => {
    //    this.showModal = onOpenModal;
    // }

    componentDidMount(){
        if (localStorage.getItem('userData')) {
            this.context.router.history.push({
                        pathname:'/',

                    });
        }
    }




    login = (e) => {
        e.preventDefault();
         axios.post('/api/signin', { 
                        user:this.state.user,
                        password:this.state.login_pass,
                    })
          .then(res => {
                //console.info(res);
                localStorage.setItem('userData', JSON.stringify(res.data));
                this.context.router.history.push({
                        pathname:'/',

                    });
//                  window.location.reload();
                    this.setState({isLogin: true});
          })
          .catch(function (error) {
            console.info(error.message);
          })
    }

    register = (e) => {
        e.preventDefault(); 
        axios.post('/api/user/add', { 
                        firstname: this.state.fname,
                        lastname:this.state.lname,
                        email:this.state.emailaddress,
                        password:this.state.password,
                        mobile:this.state.mobile 
                    },              
                )
          .then(res => {
                console.info(res);
                // this.showModal();
                 this.context.router.history.push({
                        pathname:'/otp_validate',
                    });            
          }).catch(function(error){
            alert(error.message)
          })
    }

почему вы используете слишком много файлов .html в одностраничном приложении? :/

Germa Vinsmoke 20.03.2019 09:20

Вы только проверяете localStorage на componentDidMount, поэтому, если этот компонент не размонтируется, когда вы переходите на /login, он не будет запускаться снова. Может быть, вы можете установить состояние компонента Login в родительском компоненте вместо localStorage, чтобы вам не нужно было проверять его?

Tholle 20.03.2019 09:21

@Tholle, я не понял. Не могли бы вы объяснить больше?

Sagar Kodte 20.03.2019 10:58

Будет полезно, если мы узнаем, как вы сделали перенаправление. Может быть, вы тоже можете поделиться кодом родительского компонента?

wicky 28.03.2019 03:28

@wicky Я добавил компонент регистрации входа

Sagar Kodte 28.03.2019 06:47

@SagarKodte как насчет родительского компонента, в котором вы визуализируете себя <Header/> и устанавливаете свои <Route>? На самом деле, как предложил @Tholle, вам, вероятно, следует прочитать localStorage об этом компоненте, а затем передать userData всем другим вашим дочерним компонентам в качестве реквизита.

wicky 28.03.2019 07:43

@SagarKodte сделайте console.info или console.count для компонента HeaderDidMount, и вы, вероятно, поймете, в чем проблема. Вы, вероятно, заметите, что componentDidMount не будет запущен при перенаправлении.

wicky 28.03.2019 09:42

@SagarKodte вы можете использовать history.push('/toparticularRouter');

zulqarnain 29.03.2019 12:09
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
10
8
12 456
11

Ответы 11

Напишите эти две строки в верхней части метода render(). Так:

render() {
  const userData = localStorage.getItem("userData");
  const user = JSON.parse(userData);
  if (user) {
    return (...); // logged in ui
  } else {
    return (...); // logged out ui
  }
}
componentDidMount() {
    const userData = localStorage.getItem("userData");
    const user = JSON.parse(userData);
    this.setState({ user: user });
    if (userData) {
      this.setState({ isLogin: true });
    }
    console.info(userData);
    console.info(user);

    this.setState({})
  }

ПРОБЛЕМА

Из приведенного выше кода и проблемы, с которой вы столкнулись, похоже, что у вас есть общий компонент Header, который отображается из родительского компонента Login и HomePage, возможно, из центрального компонента приложения, где вы также должны были объявить маршруты для Login и Homepage. Если это так, проблема, с которой вы столкнулись, заключается в том, что когда приложение загружается в первый раз, заголовок также загружается в это время и вызывается его метод componentDidMount. Но поскольку вы не вошли в систему в это время, компонент заголовка не получает данные пользователя, необходимые для отображения имени пользователя. Позже, когда вы выполняете фактическое действие входа в систему, сохраняете данные в локальном хранилище и перенаправляете на домашнюю страницу, заголовок не размонтируется и не перемонтируется, потому что он выходит за рамки этих отдельных компонентов Login и Homepage, поэтому событие componentDidMount не будет запущено. и в компоненте заголовка не будет обнаружено никаких изменений.

ИСПРАВИТЬ

Подход 1: Либо создайте два разных компонента Header, один для входа в систему и один для выхода из системы, и поместите их в методы рендеринга компонентов Login и HomePage соответственно. В этом случае описанная выше логика локального хранилища, написанная в componentDidMount из этих Header компонентов, должна работать правильно.

Подход 2: Поднимите пользовательские данные к родительскому компоненту Header и передайте пользовательские данные в качестве реквизита этому компоненту. В этом случае вы можете напрямую использовать это свойство в методе рендеринга Header's.

В идеале вы должны сделать два разных заголовка только в том случае, если отображаемый пользовательский интерфейс в обоих этих заголовках значительно отличается. Если это почти то же самое в состоянии входа и выхода из системы, будет избыточным добавление двух компонентов с одним и тем же пользовательским интерфейсом. В вашем случае лучше, если вы поднимете состояние до родительского компонента. Вот вам ссылка: reactjs.org/docs/lifting-state-up.html

Anvay 28.03.2019 08:37

Я не проверял все ответы, но большинство из них на самом деле неверны, кроме вашего. У меня тоже точно такая же проблема. Проблема в том, как вы сказали, ваш компонент заголовка не перерисовывается после того, как вы вошли в систему или вышли из нее. Я почти уверен, что второй подход будет работать как шарм, но я слишком ленив, чтобы поднять свои пользовательские данные до родителя. Дело в том, что, возможно, третий подход может заключаться в обновлении/перенаправлении страницы, но я не уверен, что это лучшая практика.

rawsly 28.07.2019 02:18

Попробуйте этот подход.

login = (e) => {
    e.preventDefault();
     axios.post('/api/signin', { 
                    user:this.state.user,
                    password:this.state.login_pass,
                })
      .then(res => {

            localStorage.setItem('userData', JSON.stringify(res.data));
            // delay the redirection after udpated the local storage.  
            setTimeout(() => {
              this.context.router.history.push({
              pathname:'/',
              });
              this.setState({isLogin: true});
            }, 500);

      })
      .catch(function (error) {
        console.info(error.message);
      })
}

Я не хочу использовать window.location.reload(), потому что он перезагружает страницу

Sagar Kodte 28.03.2019 07:01

Я пытаюсь сказать, что задержка this.context.router.history.push на 500 миллисекунд будет работать.

Prabu samvel 28.03.2019 07:04

window.location.relaod() прокомментирован в моем коде. Если я использую это. Код работает, но перезагружает страницу. дайте минутку, я добавляю settimeout в свой код

Sagar Kodte 28.03.2019 07:20

Да я видел это. удалить окно.location.reload(). ;)

Prabu samvel 28.03.2019 07:24

Привет, не работаю

Sagar Kodte 22.04.2019 08:23

попробуйте так в компоненте входа

login = (e) => {
    e.preventDefault();
    axios.post('/api/signin', {
        user:this.state.user,
        password:this.state.login_pass,
    })
    .then(res => {
        localStorage.setItem('userData', JSON.stringify(res.data));
        this.context.router.history.push({
            pathname:'/',
            state: { userData: JSON.stringify(res.data) }
        });
        this.setState({isLogin: true});
    })
    .catch(function (error) {
        console.info(error.message);
    })
}

и на домашней странице проверьте реквизиты в componentDidMount

componentDidMount() {
    const { userData } = this.props.location.state
    // const user = JSON.parse(userData);
    this.setState({ user: userData });
    if (userData) {
        this.setState({ isLogin: true });
    }
    console.info(userData);
    console.info(user);
}

Здесь вы передаете реквизиты на домашнюю страницу после входа в систему. Он должен работать правильно. Если нет, спросите

он дает TypeError: невозможно прочитать состояние свойства undefined на домашней странице

Sagar Kodte 22.04.2019 08:17

Внутри index.js вы должны обернуть компонент <App /> с помощью <BrowserRouter>.

Kapil Yadav 30.09.2020 13:14

В компоненте заголовка вы получаете data для отображения из двух достоверных источников. Локальное хранилище и Компоненты состояние.

Это вызовет проблемы, потому что теперь вам нужно убедиться, что два источника синхронизированы, что является проблемой, с которой вы сталкиваетесь в настоящее время.

Если я посмотрю на ваш компонент Header, вы получите состояние из LocalStorage, поэтому, если мы сможем избавиться от использования state, реакция всегда будет пытаться отобразить ваш компонент header, и вы избежите проблемы с попыткой сохранить два источника данные синхронизированы.

import React, { Component } from 'react';
import { Link } from 'react-router-dom';

const Header = (props) => {
  let userData = localStorage.getItem("userData");
  if (userData) { // i.e. user IS logged in 
     let user = JSON.parse(userData);
     return ( /* Your code for showing user data. in logout link onClick, clear the local storage */ )
  } else {
     return ( /*Your login/register header*/)
  }

}

export default Header;

Если вы беспокоитесь о производительности, сначала измерьте влияние. Если ваши userData не являются глубоко вложенными огромными json, вероятность того, что накладные расходы на производительность будут незначительными. Помните, что React, вызывающий метод render, не означает, что он будет рисовать дом.

Я делаю одно предположение: вы можете полагаться на LocalStorage как на единственный источник правды. В идеале я бы посоветовал иметь некоторую логику аннулирования кеша, но это действительно зависит от вашего варианта использования и других мер безопасности, которые у вас есть.

Я считаю, что он работает так быстро, что когда вы перенаправляете пользователя на домашнюю страницу, после входа в систему userData еще не был записан в localStorage.

Поэтому вам нужно сначала проверить, были ли данные записаны до перенаправления.

const asyncLocalStorage = {
    setItem: async function (key, value) {
        await null
        return localStorage.setItem(key, value)
    },
    getItem: async function (key) {
        await null
        return localStorage.getItem(key)
    }
}

asyncLocalStorage.setItem('user', 'data')
  .then( () => asyncLocalStorage.getItem('user') )
  .then( data => {
    console.info('User', data)
    // Redirect ...
  } )

Чувак, твоя проблема в том, что у тебя есть 3 флага, которые делают одно и то же, и ты обращаешься с ними неправильно.

например, эта строка

if (this.state.isLogin === false || this.state.isLogout === true)

will будет неверным с самого начала, вы инициализируете оба флага как false, поэтому вы перейдете прямо к условию else.

посмотрите на эту другую строку прямо здесь

 if (userData) {
  this.setState({ isLogin: true });
 }

этот код никогда не сбрасывает флаг isLogout, и метод выхода из системы также имеет проблемы

logout = e => {
    e.preventDefault();
    localStorage.clear();
    this.setState({ isLogout: true });
  };

если вы войдете в систему, то isLogin станет истинным, а isLogout останется ложным. если вы выйдете из системы, то isLogout станет истинным, а isLogin останется верным!

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

setState на componentWillMount все то же самое, что и в вашем componentDidMount, но поместите его внутрь componentWillMount

Если вы используете компонент Header независимо от входа в систему и домашнего компонента, вы должны использовать getDerivedStateFromProps(props) вместо componentDidMount, так как componentDidMount вызывается только после первоначального рендеринга.

Вы можете использовать компонент жизненного цикла getDerivedStateFromProps (реквизит, состояние), поскольку он выполняется перед первоначальным рендерингом, а также для каждого повторного рендеринга. Метод жизненного цикла компонентDidMount() вызывается после выполнения метода рендеринга, то есть только после первоначального рендеринга. Таким образом, установка состояния здесь будет отражена после повторного рендеринга компонента. Но getDerivedStateFromProps вызывается до вызова метода рендеринга. Вы можете проверить условие там, если нет изменений, просто верните null, в противном случае обновите состояние там. В состоянии getDerived из реквизита вы можете установить состояние, вернув объект. функция setState здесь не сработает, так как это статический метод. Пожалуйста, обратитесь по этой ссылке https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops

Используйте код, как показано ниже

import React, { Component } from 'react';
import { Link } from 'react-router-dom';

export default class Header extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isLogin: false,
      isLogout: false,
      user: {}
    };
  }

  static getDerivedStateFromProps(props, state){
      const userData = localStorage.getItem("userData");
      const user = JSON.parse(userData);

      if (state.user !== userData){
        return {
            user: user,
            isLogin: true
        }
      }

      return null;
  }

  logout = e => {
    e.preventDefault();
    localStorage.clear();
    this.setState({ isLogout: true, isLogin: false });
  };

  render() {
    if (this.state.isLogin === false || this.state.isLogout === true) {
      return (
        <header
          id = "kr-header"
          className = "kr-header cd-auto-hide-header kr-haslayout"
        >
          <div className = "container">
            <div className = "row">
              <div className = "col-xs-12 col-sm-12 col-md-12 col-lg-12">
                <strong className = "kr-logo">
                  <Link to = "/">
                    <img src = "images/logo.png" alt = "company logo here" />
                  </Link>
                </strong>
                <nav className = "kr-addnav">
                  <ul>
                    <li>
                      <Link
                        id = "kr-btnsignin"
                        className = "kr-btn kr-btnblue"
                        to = "login_register"
                      >
                        <i className = "icon-smiling-face" />
                        <span>Join Now</span>
                      </Link>
                    </li>
                    <li>
                      <a
                        className = "kr-btn kr-btngreen"
                        href = "dashboardaddlisting.html"
                      >
                        <i className = "icon-plus" />
                        <span>Add Listing</span>
                      </a>
                    </li>
                  </ul>
                </nav>
                <nav id = "kr-nav" className = "kr-nav">
                  <div className = "navbar-header">
                    <button
                      type = "button"
                      className = "navbar-toggle collapsed"
                      data-toggle = "collapse"
                      data-target = "#kr-navigation"
                      aria-expanded = "false"
                    >
                      <span className = "sr-only">Toggle navigation</span>
                      <span className = "icon-bar" />
                      <span className = "icon-bar" />
                      <span className = "icon-bar" />
                    </button>
                  </div>
                  <div
                    id = "kr-navigation"
                    className = "collapse navbar-collapse kr-navigation"
                  >
                    <ul>
                      <li>
                        <a href = "dashboard.html">Dasboard</a>
                      </li>
                    </ul>
                  </div>
                </nav>
              </div>
            </div>
          </div>
        </header>
      );
    } else {
      return (
        <header
          id = "kr-header"
          className = "kr-header cd-auto-hide-header kr-haslayout"
        >
          <div className = "container">
            <div className = "row">
              <div className = "col-xs-12 col-sm-12 col-md-12 col-lg-12">
                <strong className = "kr-logo">
                  <Link to = "/">
                    <img src = "images/logo.png" alt = "company logo here" />
                  </Link>
                </strong>
                <nav className = "kr-addnav">
                  <ul>
                    <li>
                      <Link
                        id = "kr-btnsignin"
                        className = "kr-btn kr-btnblue"
                        to = "login_register"
                      >
                        <i className = "icon-smiling-face" />
                                          <span>{Object.entries(this.state.user).length > 0 ? this.state.user.user.firstname : `-`}</span>
                      </Link>
                    </li>
                    <li>
                      <a
                        className = "kr-btn kr-btngreen"
                        href = "dashboardaddlisting.html"
                      >
                        <i className = "icon-plus" />
                        <span>Add Listing</span>
                      </a>
                    </li>
                    <li>
                      <a onClick = {this.logout} className = "kr-btn kr-btngreen">
                        <i className = "icon-plus" />
                        <span>Logout</span>
                      </a>
                    </li>
                  </ul>
                </nav>
                <nav id = "kr-nav" className = "kr-nav">
                  <div className = "navbar-header">
                    <button
                      type = "button"
                      className = "navbar-toggle collapsed"
                      data-toggle = "collapse"
                      data-target = "#kr-navigation"
                      aria-expanded = "false"
                    >
                      <span className = "sr-only">Toggle navigation</span>
                      <span className = "icon-bar" />
                      <span className = "icon-bar" />
                      <span className = "icon-bar" />
                    </button>
                  </div>
                  <div
                    id = "kr-navigation"
                    className = "collapse navbar-collapse kr-navigation"
                  >
                    <ul>
                      <li>
                        <a href = "dashboard.html">Dasboard</a>
                      </li>
                    </ul>
                  </div>
                </nav>
              </div>
            </div>
          </div>
        </header>
      );
    }
  }
} 

Другие вопросы по теме