Нативная карта React (собственная база) onPress не работает

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

Мой вид карты:

<Card>
  <CardItem button onPress={this._OnButtonPress(news.id)}>
    <Left>
      <Body>
        <Text style={styles.cardText}>{news.title}</Text>
      </Body>
    </Left>
  </CardItem>
  <CardItem>
    <Left>
        <Icon style={styles.icon} name="chatbubbles" />
        <Text>{news.comments} comments</Text>
    </Left>
    <Right>
      <Text>{news.published}</Text>
    </Right>
  </CardItem>
</Card>

Я пытаюсь передать переменную в функцию onButtonPress()

_OnButtonPress(newsID) {
  Alert.alert(newsID.toString());
}

Чтобы проверить событие onPress, все, что я сделал, это предупредил параметр.

Я не вижу ничего плохого, но все же я получил эту ошибку

Кто-нибудь знает, как я могу это исправить и что я делаю неправильно здесь. Заранее спасибо.

Обновить

Мой обновленный класс:

import React, { Component } from "react";
import {
  Image,
  ListView,
  StyleSheet,
  Text,
  View,
  Alert
} from 'react-native';

import {
  Container,
  Header,
  Left,
  Right,
  Button,
  Card,
  CardItem,
  Icon,
  Body,
  Content,
  Logo
} from 'native-base';

import styles from "./styles";

const logo = require("../../../img/f1today.png");

var REQUEST_URL = 'http://v2.first-place.nl/test/news.json';

class News extends Component {
  constructor(props) {
    super(props);

    this._OnButtonPress = this._OnButtonPress.bind(this);

    this.state = {
      dataSource: new ListView.DataSource({
        rowHasChanged: (row1, row2) => row1 !== row2,
      }),
      loaded: false,
    };
  }

  _OnButtonPress(newsID) {
    Alert.alert(newsID.toString());
  }

  componentDidMount() {
    this.fetchData();
  }

  fetchData() {
    fetch(REQUEST_URL)
      .then((response) => response.json())
      .then((responseData) => {
        this.setState({
          dataSource: this.state.dataSource.cloneWithRows(responseData.articles),
          loaded: true,
        });
      })
      .done();
  }

  render() {

    if (!this.state.loaded) {
      return this.renderLoadingView();
    }

    return (
      <Container style={styles.container}>
        <Header
          style={{ backgroundColor: "#fff" }}
          androidStatusBarColor="#f05423"
          iosBarStyle="light-content">

        <Left>
          <Button
            transparent
            onPress={() => this.props.navigation.navigate("DrawerOpen")}
          >
            <Icon name="ios-menu" style={{color: 'black'}} />
          </Button>
        </Left>
        <Body> 
          <Image source={logo} style={styles.headerLogo} />
        </Body>
        <Right />

      </Header>

      <Content padder>

        <ListView
          dataSource={this.state.dataSource}
          renderRow={this.renderNews}
          style={styles.listView}
        />

      </Content>
    </Container>
    );
  }

  renderLoadingView() {
    return (
      <View style={styles.loading}>
        <Text>
          Loading news...
        </Text>
      </View>
    );
  }

  renderNews(news) {
    return (
      <Card>
        <CardItem button onPress={()=> this._OnButtonPress(news.id)}>
          <Left>
            <Body>
              <Text style={styles.cardText}>{news.title}</Text>
            </Body>
          </Left>
        </CardItem>
        <CardItem>
          <Left>
              <Icon style={styles.icon} name="chatbubbles" />
              <Text>{news.comments} comments</Text>
          </Left>
          <Right>
            <Text>{news.published}</Text>
          </Right>
        </CardItem>
      </Card>
    );
  }
}

export default News;

person abbob1    schedule 27.10.2017    source источник
comment
Не рекомендуется передавать параметры функции внутри метода render, так как он будет отображать их каждый раз при обновлении компонента... если, конечно, это не является абсолютно необходимым.   -  person assembler    schedule 27.10.2017


Ответы (4)


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

renderNews(news) { }

Если вы объявите свой метод таким образом, у вас не будет этого в вашем методе, и, поскольку «это» не определено, все методы вызовут ошибку, потому что вы пытаетесь получить доступ к «undefined.methodName()». Сказав это, вы должны «привязать» контекст к вашему методу, объявив его следующим образом:

renderNews = (news) => { }

Теперь у вас есть контекст, прикрепленный к методу, и «это» доступно внутри.

person EnriqueDev    schedule 27.10.2017
comment
Благодарю вас! это ответ - person abbob1; 31.10.2017

Вы должны обернуть свой CardItem TouchableOpacity или любым другим сенсорным элементом. И дайте функцию onPress этому сенсорному элементу.

<TouchableOpacity onPress={() => //your function}
    <CardItem>
    </CardItem>
</TouchableOpacity>

Примечание. Убедитесь, что вы используете компонент <TouchableOpacity>, связанный с пакетом react-native, а не с пакетом react-native-gesture-handler. Редактор кода Visual Studio может автоматически импортировать из react-native-gesture-handler, что не работает в данном конкретном случае.

Правильный пакет:

import { TouchableOpacity } from 'react-native';

Неправильный пакет:

import { TouchableOpacity } from 'react-native-gesture-handler';
person burakkesepara    schedule 27.10.2017
comment
ах, извините, не понял, что вы даете функцию onPress для CardItem. поэтому вы должны обернуть свой CardItem сенсорным элементом. это должно выглядеть как в моем ответе, который я отредактировал. - person burakkesepara; 27.10.2017
comment
Спасибо за помощь, но проблема заключалась в том, что функция не была найдена за пределами карты. - person abbob1; 31.10.2017

Для меня я оставил кнопку = {true} выключенной, когда я добавил, она работает. См. пример ниже.

  <CardItem 
       button={true}
       onPress={() => {this.cardSelected(item.name)}}
       style={{paddingTop:0,paddingBottom:0,paddingLeft:0,paddingRight:0}}>
      <Image  source={item.img} style={{flex:1,resizeMode: 'cover',height: 175}} />
      <Text style={styles.cardheading}>{item.name}</Text>
        <Image source={cardline} style={styles.cardline}/>
        <Text style={styles.cardtext}> {item.text}</Text>

      </CardItem>
person sonic_ninja    schedule 04.12.2017
comment
Это больше похоже на нативную базовую библиотеку. В отличие от TouchableOpacity, это не влияет на другие мои представления. Спасибо - person Arun K; 06.11.2020

Вам нужно привязать эту функцию. Напишите следующий код внутри функции-конструктора:

this._OnButtonPress = this._OnButtonPress.bind(this);

Кроме того, изменил onPress следующим образом:

onPress={()=> this._OnButtonPress(news.title)}

Наконец, я мог видеть, что onPress был написан на компоненте. Скорее вы должны определить/записать его внутри этого контейнера.

person Rohan Kangale    schedule 27.10.2017
comment
Теперь, когда я нажимаю CardItem, я получаю следующую ошибку: i.stack.imgur.com/VbAbA .png - person abbob1; 27.10.2017
comment
Вы обновили функцию конструктора? написав привязку? - person Rohan Kangale; 27.10.2017
comment
Скажи мне одну вещь, у тебя есть компонент. Вы должны написать onPress внутри компонента. Не здесь. - person Rohan Kangale; 27.10.2017
comment
Да, я добавил это._OnButtonPress = this._OnButtonPress.bind(this); конструктору - person abbob1; 27.10.2017
comment
Пожалуйста, смотрите мой обновленный ответ. Обновите событие onPress. - person Rohan Kangale; 27.10.2017
comment
Я уже обновил событие opPress, изображение, которое я отправил, является ошибкой - person abbob1; 27.10.2017
comment
Вы получаете сообщение об ошибке во время выполнения или после события onPress? - person Rohan Kangale; 27.10.2017