Я сохраняю пользовательские данные в 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)
})
}
Вы только проверяете localStorage на componentDidMount, поэтому, если этот компонент не размонтируется, когда вы переходите на /login, он не будет запускаться снова. Может быть, вы можете установить состояние компонента Login в родительском компоненте вместо localStorage, чтобы вам не нужно было проверять его?
@Tholle, я не понял. Не могли бы вы объяснить больше?
Будет полезно, если мы узнаем, как вы сделали перенаправление. Может быть, вы тоже можете поделиться кодом родительского компонента?
@wicky Я добавил компонент регистрации входа
@SagarKodte как насчет родительского компонента, в котором вы визуализируете себя <Header/> и устанавливаете свои <Route>? На самом деле, как предложил @Tholle, вам, вероятно, следует прочитать localStorage об этом компоненте, а затем передать userData всем другим вашим дочерним компонентам в качестве реквизита.
@SagarKodte сделайте console.info или console.count для компонента HeaderDidMount, и вы, вероятно, поймете, в чем проблема. Вы, вероятно, заметите, что componentDidMount не будет запущен при перенаправлении.
@SagarKodte вы можете использовать history.push('/toparticularRouter');



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Напишите эти две строки в верхней части метода 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
Я не проверял все ответы, но большинство из них на самом деле неверны, кроме вашего. У меня тоже точно такая же проблема. Проблема в том, как вы сказали, ваш компонент заголовка не перерисовывается после того, как вы вошли в систему или вышли из нее. Я почти уверен, что второй подход будет работать как шарм, но я слишком ленив, чтобы поднять свои пользовательские данные до родителя. Дело в том, что, возможно, третий подход может заключаться в обновлении/перенаправлении страницы, но я не уверен, что это лучшая практика.
Попробуйте этот подход.
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(), потому что он перезагружает страницу
Я пытаюсь сказать, что задержка this.context.router.history.push на 500 миллисекунд будет работать.
window.location.relaod() прокомментирован в моем коде. Если я использую это. Код работает, но перезагружает страницу. дайте минутку, я добавляю settimeout в свой код
Да я видел это. удалить окно.location.reload(). ;)
Привет, не работаю
попробуйте так в компоненте входа
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 на домашней странице
Внутри index.js вы должны обернуть компонент <App /> с помощью <BrowserRouter>.
В компоненте заголовка вы получаете 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>
);
}
}
}
почему вы используете слишком много файлов .html в одностраничном приложении? :/