Я следую учебнику для начинающих от Pluralsight, при отправке формы значение передается методу компонента addUser
, и мне нужно отправить userName в this.state.users
, но я получаю ошибку
App.jsx:14 Uncaught TypeError: Cannot read property 'users' of undefined
Компонент
import React from 'react'
import User from 'user'
import Form from 'form'
class Component extends React.Component {
constructor() {
super()
this.state = {
users: null
}
}
// This is triggered on form submit in different component
addUser(userName) {
console.log(userName) // correctly gives String
console.log(this.state) // this is undefined
console.log(this.state.users) // this is the error
// and so this code doesn't work
/*this.setState({
users: this.state.users.concat(userName)
})*/
}
render() {
return (
<div>
<Form addUser={this.addUser}/>
</div>
)
}
}
export default Component
9 ответов
Когда вы вызываете {this.addUser}
, он вызывается, здесь this
является экземпляром вашего класса (компонента), и поэтому он не дает вам ошибки, потому что метод addUser
существует в вашем классе scope
, но когда вы используете метод addUser
, вы используете this
для обновления state
, которые существуют в область действия класса (компонента), но в настоящее время вы находитесь в области действия метода addUser
и поэтому выдает ошибку, как в addUser
области видимости, вы ничего не получаете, например, состояние, пользователь и т. д. Поэтому для решения этой проблемы вам нужно связать this
во время вызова метода addUser
. Так что ваш метод всегда знает экземпляр this
.
Таким образом, последнее изменение в вашем коде будет выглядеть так:
<Form addUser={this.addUser.bind(this)}/>
< Сильный > ИЛИ сильный >
this
DOM
Таким образом, вы можете сделать это следующим образом:
constructor(props) {
super(props);
this.state = {
users: null
}
this.addUser=this.addUser.bind(this);
}
И теперь вы можете называть это как обычно: -
<Form addUser={this.addUser}/>
Я надеюсь, что это сработает, И я дал вам понять.
У меня была та же проблема, но моя проблема была в попытке получить доступ к this.state до завершения вызова this.state = { ... }
. Делал что-то вроде этого this.state = { ...this.function1() }
и function1 = () => { a: this.state.b }
. Надеюсь, это поможет кому-то
Подходы @Vinit Raj работают отлично - поэтому я предпочитаю использовать синтаксис функции стрелки, как это.
<Form addUser={ () => this.addUser() }/>
Используя такую анонимную функцию, вам не нужно никуда связывать ее.
Если вы предпочитаете использовать функцию стрелки, сделайте это. Синтаксис функции стрелки, как показано ниже
addUser = event => {
const { value } = event.target;
console.log("value", value);
}
Чтобы предотвратить вызов этой функции при каждом рендеринге или рендеринге, необходимо
+ Изменить
<Form addUser={this.addUser}/>
К
<Form addUser={() => this.addUser()}/>
Так что addUser вызывается только тогда, когда событие происходит / запускается
В вашем случае, объявив свою функцию как функцию жирной стрелки, вы добавляете контекст и удаляете требование связываться с этим. Это работает так же, как и другие решения, но значительно упрощает как запись, так и чтение. Просто поменяй ...
addUser(userName) {
console.log(userName) // correctly gives String
console.log(this.state) // this is undefined
console.log(this.state.users) // this is the error
// and so this code doesn't work
/*this.setState({
users: this.state.users.concat(userName)
})*/
}
Чтобы ...
addUser = (userName) => {
console.log(userName) // correctly gives String
console.log(this.state) // this is undefined
console.log(this.state.users) // this is the error
// and so this code doesn't work
/*this.setState({
users: this.state.users.concat(userName)
})*/
}
А все остальное может остаться прежним.
Я не думаю, что другие ответы объясняют это очень хорошо. По сути, проблема в том, что ключевое слово Javascript this
является безумным (MDN очень щедро говорит, что оно " в JavaScript ведет себя немного иначе, чем в других языках ").
TL; DR состоит в том, что this
не обязательно является классом, в котором определен метод. Когда вы используете this.addUser
в своем элементе <Form>
, this
фактически является {{ X4}} объект! Я не уверен, почему React делает это - я не могу понять, почему кто-то этого захочет, но это легко проверить. Просто поместите console.log(this)
в addUser
и вы обнаружите, что это экземпляр Form
.
В любом случае, решение довольно простое - используйте функцию стрелки. Функции стрелок делают копию this
в том месте, где они определены. Так что, если вы поместите один в вашу функцию рендеринга, как и другие люди предложили:
<Form addUser={() => this.addUser()}/>
Затем, когда render()
запущен, this
будет ссылаться на объект Component
, функция стрелки создаст его копию, а затем при запуске она будет использовать эту копию. Это в основном сокращение для этого кода (и это то, что люди делали до функций стрелок):
render() {
const that = this; // Make a copy of this.
return (
<div>
<Form addUser={function() { return that.addUser; }}/>
</div>
)
}
Кроме того, как уже упоминали другие люди, создание новой функции при каждом вызове функции рендеринга может повлиять на производительность, поэтому лучше захватывать this
один раз где-нибудь еще. Я думаю, что это лучший подход, чем то, что предложили другие люди:
class Component extends React.Component {
constructor() {
super()
this.state = {
users: null
}
}
// This is triggered on form submit in different component
addUser = (userName) => {
this.setState({
users: this.state.users.concat(userName)
})
}
render() {
return (
<div>
<Form addUser={this.addUser}/>
</div>
)
}
}
Но это мой первый день, когда я использую React, и я обычно стараюсь избегать использования языков, столь же лающих, как Javascript, так что принимайте все это с небольшим количеством соли!
Проблема в этом контексте, поэтому используйте
<form onSubmit={(event)=>this.addUser(event)}>
// Inputs
</form>
addUser(event){
event.preventDefault()
// Code this.state
}
Хорошим примером является привязка метода к классу в функции конструктора. Видеть https://reactjs.org/docs/handling-events.html
import React from 'react'
import User from 'user'
import Form from 'form'
class Component extends React.Component {
constructor() {
super()
this.state = {
users: null
}
this.addUser = this.addUser.bind(this);
//bind functions which need access to "this"v in the constructor here.
}
// This is triggered on form submit in different component
addUser(userName) {
console.log(userName) // correctly gives String
console.log(this.state) // this is undefined
console.log(this.state.users) // this is the error
// and so this code doesn't work
/*this.setState({
users: this.state.users.concat(userName)
})*/
}
render() {
return (
<div>
<Form addUser={this.addUser}/>
</div>
)
}
}
export default Component
Просто используйте async в функции
addUser =async (userName) => {
console.log(this.state.users)
}
Это будет работать нормально
Похожие вопросы
Связанные вопросы
Новые вопросы
reactjs
React - это библиотека JavaScript для создания пользовательских интерфейсов. Он использует декларативную компонентную парадигму и стремится быть одновременно эффективным и гибким.