React Native: this.setState не является функцией
Я вижу здесь несколько вопросов, относящихся к этой же проблеме, но, похоже, не соответствует той проблеме, которая у меня есть, и немного сложнее.
Я участвую в процессе обучения ReactJS и React Native. Я посреди чтения и следуя примерам кода из книги "Learning React Native": https://github.com/bonniee/learning-react-native
По какой-то причине вызов this.setState в коде ниже, когда вызывается функция handleTextChange, вызывает "this.SetState не является функцией". ошибка. Почему мой вопрос? В отличие от других вопросов по этой же проблеме, я не считаю, что мой вызов this.stateState похож на функцию обратного вызова или оператор if. Почему это undefined?
Вот мой код:
class WeatherProject extends Component {
constructor(props) {
super(props);
this.state = {
zip: "",
forecast: null
};
}
_handleTextChange(event) {
this.setState({zip: event.nativeEvent.text});
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
You input {this.state.zip}.
</Text>
<TextInput
style={styles.input}
onSubmitEditing={this._handleTextChange}/>
</View>
);
}
}
Ответы
Ответ 1
Не используйте привязку внутри рендера. bind - довольно дорогостоящая операция и должна произойти только один раз. у вас есть два варианта:
либо привязать функцию в конструкторе:
this._handleTextChange = this._handleTextChange.bind(this);
или используйте функцию стрелки:
onSubmitEditing={(e) => this._handleTextChange(e)} />
Изменить
Очевидно, что функции стрелок внутри рендера также являются плохой практикой (спасибо to Adam Terlson в комментариях и ответах ниже). Вы можете прочитать eslint docs, который гласит:
Функция привязки или функция стрелки в JSX prop создаст совершенно новую функцию для каждого отдельного рендеринга. Это плохо для производительности, так как это приведет к тому, что сборщик мусора будет вызван больше, чем это необходимо.
Использование функций стрелок, очевидно, не так плохо, как использование bind, но, тем не менее, следует избегать.
Ответ 2
Проблема связана с контекстом, как указано в других комментариях и ответах здесь.
Однако производительность самого связывания не является проблемой. Еще более важная проблема заключается в том, что использование привязки или стрелок в методах рендеринга создает новую функцию для каждого рендеринга, что приводит к изменению реквизита для получающего их ребенка, заставляя повторную визуализацию.
У вас есть два жизнеспособных варианта:
class WeatherProject extends Component {
constructor(props) {
super(props);
this._handleTextChange = this._handleTextChange.bind(this);
}
// ...
}
Или вы можете использовать обозначение свойства класса и назначить функции стрелок, если вы используете для него плагин babel.
class WeatherProject extends Component {
constructor(props) {
super(props);
// ...
}
handleTextChange = (event) => {
this.setState({zip: event.nativeEvent.text});
}
// ...
}
Я настоятельно рекомендую вам использовать пакет eslint с отредактировать рекомендуемые правила. Он будет ловить ошибки, например, используя bind/стрелки в вашем рендере, а также сказать, что подчеркивающие префиксные функции уродливы и абсолютно не нужны в React.:)
Ответ 3
Что касается функции стрелки, вам также необходимо изменить функцию _handleTextChange (событие). Другие ответы не говорили о том, как изменить нормальную функцию на функцию стрелки. Таким образом, предоставление в качестве ответа, который может помочь другим
Вам нужно изменить функцию обработчика
от
_handleTextChange(event) {
this.setState({zip: event.nativeEvent.text});
}
к
_handleTextChange = event => {
this.setState({zip: event.nativeEvent.text});
}
Ответ 4
Я не могу решить это. Я перепробовал все решения, которые я могу найти в Интернете. Вот мой код:
constructor() {
super();
this.state = {
list: [],
favourites: []
};
Это функции
_favouriteIcon = (item) => {
let color = this.getState('favourites').indexOf(item.vehicleid)!== -1?'#ffb30c':'#cacaca';
return <TouchableOpacity onPress={() => this._toggleFavourite(item)}>
<Icon
name='star'
color={'${color}'}/>
</TouchableOpacity>
};
_renderItem = (item, rowId, sectionId) => {
console.log(item);
let text = '';
let subText = '';
return <TouchableOpacity onPress={() => this.onPress(item)}>
<ListItem
leftIcon = {this._favouriteIcon(item).bind(this)}
title={'${text}'}
subtitle={'${subText}'}
containerStyle={{borderBottomWidth: 0}}
/>
</TouchableOpacity>
};
render() {
return (
<View style={styles.container}>
<ExpandableList
dataSource={this.state.list}
headerKey="title"
memberKey="member"
renderRow={this._renderItem.bind(this)}
renderSectionHeaderX={this._renderSection}
/>
<Footer/>
</View>
);
}