React Native, как заменить URL-адрес изображения при ошибке?

У меня есть приложение, которое отображает несколько изображений, которые я загружаю из API. Теперь проблема заключается в том, что срок действия некоторых изображений истек, что вызывает проблему на Android, в Android экран начинает отставать, как только просроченное изображение загружается на экран.

Я попытался заменить источник изображения onError={() => this.imgRefs[img_unique_id].setNativeProps({src: [{uri: this.state.workingUri}]})} этим методом, но он не работает. Я не могу использовать локальное состояние, так как оно не сохраняет вывод в локальном состоянии.

Я пробовал следующий код

  <Image  
      source={image.url} 
      progressiveRenderingEnabled={true}
      ref={item.id} 
      onError={(e) => this.refs[item.id].setNativeProps({source: [{uri: "working image URL"}]})} 
      resizeMethod={"scale"}>
   </Image>      

Приведенный выше код дает мне неопределенную ошибку setNativeProps, и если я не использую onError на Android, он показывает мне ошибку утечки памяти.


person Tushar Cheulkar    schedule 17.04.2019    source источник
comment
Почему в этом случае нельзя использовать локальное состояние?   -  person gbalduzzi    schedule 17.04.2019


Ответы (2)


Вот полный пример этого. Чтобы иметь собственное состояние для каждого элемента FlatList, я создал класс.

import React, { Component, PureComponent } from 'react';
import { FlatList, Text, View, Image } from 'react-native';

class ItemClass extends PureComponent {
  state = {
    isImageExit: null
  }
  componentWillMount = () => {
    const { task } = this.props;
    Image.getSize(task.url, (width, height) => {
        if(width>0){
            this.setState({ isImageExit: true });
        }
        else{
            this.setState({ isImageExit: false });
        }
    }, () => {
      this.setState({ isImageExit: false });
    });
  }

  render() {
    const { isImageExit } = this.state;
    const { task } = this.props;
    const url = isImageExit ? task.url : 'https://dummyimage.com/600x400/000/fff';
    if (isImageExit === null) {
      return null;
    }
    return (
      <Image
        style={{ height: 200, width: 200 }}
        source={{ uri: url }}
      />
    );
  }
}

export default class App extends Component {
  render() {
    const data = [
      { url: 'url' },
      { url:'https://cdn.pixabay.com/photo/2017/08/05/18/53/mountain-2585069_1280.jpg' },
    ];
    return (
      <View style={{alignItems: 'center', top: 50}}>
          <FlatList
            data={data}
            renderItem={({ item }) => <ItemClass task={item} />}
          />
      </View>
    );
  }
}
person akcoban    schedule 17.04.2019
comment
ваш код работал отлично, но проблема остается той же, как только изображение ошибки появляется в представлении, приложение становится медленным. - person Tushar Cheulkar; 17.04.2019
comment
Вместо того, чтобы ждать, пока изображение перейдет в состояние ошибки, как я могу использовать getSize для предварительной загрузки изображения? - person Tushar Cheulkar; 17.04.2019
comment
Обновил, может так лучше? Во-первых, image.getSize попытается загрузить и получить размер изображения. Пока это работает, ничего не будет отображаться, или вы можете отображать загрузочный компонент или то, что хотите. Когда getSize завершится, изображение тоже будет отображаться. - person akcoban; 17.04.2019
comment
Я реализовал изменение, оно все еще медленное, я думаю, что изображения делают FlatList медленным после загрузки. Пробовал без картинок, работает нормально. - person Tushar Cheulkar; 17.04.2019

Я думаю, что вы должны использовать данные, полученные от API, и соответственно установить состояние внутри componentWillReceiveProps, потому что я думаю, что настройка состояния — лучший способ достичь этого результата. .

 this.setState = { image: { uri: 'image_uri_from_api' } }

Внутри <Image> добавляем -

 <Image style={ your_custom_style }
       source={ this.state.image }
       onError={ this.onError.bind(this) }
 />

Внутри onError добавьте это -

onError(error){
   this.setState({ image: require('your_local_image.path')})
 }

Надеюсь, теперь это работает!

person abhinandan sharma    schedule 17.04.2019
comment
Это реакция нативная, а не веб-реакция - person gbalduzzi; 17.04.2019
comment
спасибо, что сообщили мне. Я обновил ответ соответственно. - person abhinandan sharma; 17.04.2019
comment
Динамически загружается несколько изображений, как мне поступить в этой ситуации? - person Tushar Cheulkar; 17.04.2019
comment
да, я использую плоский список. На iOS это обрабатывается в конце ОС, на Android это создает утечку памяти. - person Tushar Cheulkar; 17.04.2019
comment
Есть ли способ, которым я могу передать функцию в источнике, которая сначала извлекает изображение, и в зависимости от размера я могу вернуть изображение или your_local_image? - person Tushar Cheulkar; 17.04.2019
comment
вы можете попробовать одну вещь, если это возможно. Метод элемента рендеринга внутри проверяет ширину, если она больше 0, возвращает ‹Image style={ your_custom_style } source={ this.state.image } /› иначе возвращает ‹Image style={ your_custom_style } source ={ your_local_image_uri } /› - person abhinandan sharma; 17.04.2019