React Native CameraRoll.getPhotos API не отображает результаты

Привет у меня есть следующий класс, где я пытаюсь получить фотографии с камеры и показать их.

class CameraRollProject extends Component {
  constructor(props) {
    super(props);
    this.state = {
     images: []
    };
  }

  componentWillMount() {
    const fetchParams = {
      first: 25,
    };
    CameraRoll.getPhotos(fetchParams, this.storeImages, this.logImageError);
  }

  storeImages(data) {
    const assets = data.edges;
    const images = assets.map((asset) => asset.node.image);
    this.state.images =  images;
  }

  logImageError(err) {
    console.log(err);
  }

  render() {
      return (
        <ScrollView style={styles.container}>
          <View style={styles.imageGrid}>
            { this.state.images.map((image) => <Image style={styles.image} source={{ uri: image.uri }} />) }
          </View>          
        </ScrollView>
      );
  }
};

export default CameraRollProject;

Проблема в том, что моя функция рендеринга вызывается до того, как мое обещание CameraRoll.getPhotos будет решено. Так что я не получаю никаких фотографий.

Чтобы решить эту проблему, я изменил свою программу на следующие

render() {
      return CameraRoll.getPhotos(fetchParams, this.storeImages, this.logImageError)
        .then(() => {
          return (
            <ScrollView style={styles.container}>
              <View style={styles.imageGrid}>
                { this.state.images.map((image) => <Image style={styles.image} source={{ uri: image.uri }} />) }
              </View>          
            </ScrollView>
          );
        });
  }

Однако это дает мне следующую ошибку

Экран ошибки

Что я могу сделать в вышеуказанной ситуации? Как я могу убедиться, что рендер работает только после разрешения CameraRoll.getPhotos.

3 ответа

Решение

Поэтому я решил эту проблему. Основной причиной моей проблемы было то, что я не использовал CameraRoll.getPhotos как обещание. Я передавал неверный параметр внутри функции. Чтобы решить эту проблему, я избавился от следующих функций

 storeImages(data) {
    const assets = data.edges;
    const images = assets.map((asset) => asset.node.image);
    this.state.images =  images;
  }

  logImageError(err) {
    console.log(err);
  }

И сделайте мой CameraRoll.getPhotos как следующий

CameraRoll.getPhotos({first: 5}).then(
  (data) =>{
    const assets = data.edges
    const images = assets.map((asset) => asset.node.image);
        this.setState({
          isCameraLoaded: true,
          images: images
        })
  },
  (error) => {
     console.warn(error);
  }
);

Вот мой полный код, чтобы получить фотографии с CameraRoll в реагирующем на всякий случай, если кому-то интересно

class CameraRollProject extends Component {
  constructor(props) {
    super(props);
    this.state = {
     images: [],
     isCameraLoaded: false
    };
  }

  componentWillMount() {
    CameraRoll.getPhotos({first: 5}).then(
      (data) =>{
        const assets = data.edges;
        const images = assets.map((asset) => asset.node.image);
        this.setState({
          isCameraLoaded: true,
          images: images
        })
      },
      (error) => {
        console.warn(error);
      }
    );
  }

  render() {
      if (!this.state.isCameraLoaded) {
        return (
          <View>
            <Text>Loading ...</Text>
          </View>
          );
      }
      return (
        <ScrollView style={styles.container}>
          <View style={styles.imageGrid}>
            { this.state.images.map((image) => <Image style={styles.image} source={{ uri: image.uri }} />) }
          </View>          
        </ScrollView>
      );
  }
};

export default CameraRollProject;

Я думаю, что вы должны использовать ответную реакцию

У вас есть много параметров, чтобы получить изображение, как вы хотите

  selectPhotoTapped() {
    const options = {
      title: 'Choose a picture',
      cancelButtonTitle: 'Back',
      takePhotoButtonTitle: 'Take a picture...',
      chooseFromLibraryButtonTitle: 'Choose from my pictures..',
      quality: 1,
      maxWidth: 300,
      maxHeight: 300,
      allowsEditing: true,
      mediaType: 'photo',
      storageOptions: {
        skipBackup: true
      }
    }

с ним гораздо легче обращаться, чем с CameraRollProject, и документация очень хорошо объяснена. для того, что бы вы делали, это прекрасно подходит. (Работает на iOS и Android)

Одним из способов сделать это было бы использовать ListView а не Scrollview потому что вы можете использовать datasource, Вот пример того, как вы могли бы сделать это:

constructor(props) {
  super(props);

  const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
  this.state = { dataSource: ds.cloneWithRows([]) };

  this.loadPhotos();
}

loadPhotos() {
  const fetchParams = {
    first: 25,
  };

  CameraRoll.getPhotos(fetchParams).then((data) => {
    this.state.dataSource.cloneWithRows(data.edges);
  }).catch((e) => {
    console.log(e);
  });
}

Таким образом, вы отображаете пустой список (и состояние загрузки для хорошего UX), а затем, как только выборка завершена, вы устанавливаете данные в ListView,

Если вы хотите придерживаться ScrollView и сопоставленные изображения, вам также понадобится какое-то состояние загрузки до загрузки фотографий. Надеюсь это поможет.

Другие вопросы по тегам