Я новичок в ReactJS, но я хотел бы создать простой домен с возможностью входа и выхода. Я храню учетные данные пользователя в AsyncStorage. Вот мой index.js:

..
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';
..

class Index extends Component {

    render() {
        return (
            <Router>
                <Switch>
                    <Route path='/' exact component={Home}/>
                    <Route path='/login' component={Login}/>
                    <Route path='/welcome' component={Welcome}/>
                </Switch>
            </Router>
        );
    }

}

ReactDOM.render(<Index />, document.getElementById('root')); registerServiceWorker();

На странице Главная есть кнопка, которая перемещается на страницу входа:

<Button color="primary" onClick={() => {this.props.history.push("/login")}}>Sign In</Button>

Компонент Логин содержит форму, которая при отправке вызывает данный метод:

this.props.history.push("/welcome");

Наконец, на странице Добро пожаловать у меня есть следующая кнопка :

class Welcome extends Component {

    handleLogout() {
        this.props.history.push("/");
    }

    render() {
        return (
            <div>
                <h1>Hello!</h1>
                <Button onClick={this.handleLogout}>Logout</Button>
            </div>
        );
    }
}

export default withRouter(Welcome);

Я хотел бы сказать, что каждый компонент ( Главная , Логин , Добро пожаловать ) обернут в компонент сRouter, но как только я нажимаю Кнопка на странице приветствия возникает ошибка:

TypeError: Невозможно прочитать свойство 'history' из неопределенного

Любая помощь будет оценена :)

0
J.Kennsy 21 Авг 2018 в 18:06

4 ответа

Лучший ответ

В javascript значение this не определяется до тех пор, пока функция не будет вызвана. А поскольку onClick - это то, что происходит асинхронно, handleLogout будет вызываться без контекста, что означает, что this привязан к объекту окна в нестрогом режиме или не определен в строгом режиме. Вы, очевидно, находитесь в нестрогом режиме, поэтому this.props.history.push такой же, как window.props.history.push. window.props не определен, что приводит к ошибке.

Есть несколько способов исправить это:

1) Используйте функцию стрелки в рендере. Функции стрелок имеют то же значение this, что и при их объявлении, поэтому this будет равен вашему компоненту

<Button onClick={(event) => this.handleLogout(event)}/>

2) Явно свяжите вашу функцию handleLogout в вашем конструкторе. Это создает новую функцию, для которой значение this заблокировано.

class Welcome extends Component {
  constructor(props) {
    super(props);
    this.handleLogout = this.handleLogout.bind(this);
  }

  handleLogout() {
    this.props.history.push("/");
  }
  //etc
}

3) Если вы используете babel-plugin-transform-class -properties, определите handleLogout как функцию стрелки:

class Welcome extends Component {
  handleLogout = () => {
    this.props.history.push("/");
  }
  //etc
}
2
Nicholas Tower 21 Авг 2018 в 15:28

Это связано с тем, как this определяется. Вы определяете свой handleLogout в контексте вашего компонента, но затем вы передаете его в другой контекст и выполняете его там. this будет другим в этом контексте, поэтому реквизит не определен.

По сути, если вы передаете функции в другой контекст (и вам нужен доступ к чему-то из this, например, к реквизитам или состоянию, вам нужно привязать функцию к версии компонентов this. Вы можете сделать это одним из двух распространенных способов

В конструкторе вашего компонента:

constructor(props) {
   super(props)
   this.handleLogout = this.handleLogout.bind(this);
}

Или путем определения вашего метода с помощью функции со стрелкой (это «автоматическое связывание»), но этот метод не полностью утвержден, поэтому, скорее всего, потребуется заполнение по типу babel:

handleLogout = () => { // function code }
2
Geraint 21 Авг 2018 в 17:16

Это действительно распространенная проблема, с которой сталкиваются люди: вы не передаете правильную область действия функции-обработчику. Таким образом, когда вызывается handleLogout, область действия (представленная как this) не включает в себя реквизиты. Вам необходимо связать this с этой функцией-обработчиком, прежде чем она будет передана дочернему компоненту. Вы можете сделать это либо используя функцию стрелки, когда передаете функцию кнопке (функция стрелки автоматически пропускает область видимости):

<Button
    onClick={() => this.handleLogout()}
>
    Logout
</Button>

Или вы можете привязать это к функции-обработчику в конструкторе:

class Welcome extends Component {
    constructor(props) {
        super(props);
        this.handleLogout = this.handleLogout.bind(this);
    }

Всякий раз, когда вы видите ошибку в React, которая указывает, что реквизиты не определены, «this» должно быть первым, что вы проверяете. (каламбур предназначен!)

1
Steve Archer 21 Авг 2018 в 15:15

Вы должны использовать React-Router с Router HOC следующим образом:

введите описание изображения здесь тогда вы можете прочитать историю из this.props

0
hossein dindar 21 Авг 2018 в 15:59
51951656