объявление переменных быстрее, чем setState - PullRequest
0 голосов
/ 20 января 2020

Моя команда и я работаем над страницей профиля, на которой показана фотография профиля и биография. Мы использовали библиотеку expo-image-picker для пользователей, чтобы выбрать нужное изображение и показать изображение в приложении. Я также хотел бы загрузить изображение на s3, где будут храниться изображения сотрудника. Проблема, с которой я сталкиваюсь сейчас, заключается в том, что params.ImageUri дает мне локальный файл вместо ссылки s3. Вот как выглядят мои функции.

У меня есть функция selectImage (), которая заставит пользователя выбрать изображение из своей галереи. Затем данные будут сохранены в this.state.items [0] .imageUrl , который представляет собой данные из Web API. После того, как я вызываю эту функцию, значение this.state.items [0] .imageUrl является локальным файлом. Эта функция вызывается, когда пользователь нажимает на Картинку профиля .

  selectImage = async () => {

    const cancelImageUrl = this.state.items[0].imageUrl

    let result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      allowsEditing: true,
      aspect: [4, 3],
      quality: 1
    });

    const file = {
      uri: result.uri,
      name: 'IMG_' + Math.random(4000),
      type: 'image/jpg'
    }

    if (!result.cancelled) {
      this.setState({
        items: this.state.items.map((item, i) =>
          i == 0 ?
            { ...item, imageUrl: file.uri } : item),
        file: file
      })
    }
    else {
      this.setState({
        items: this.state.items.map((item, i) =>
          i == 0 ?
            { ...item, imageUrl: cancelImageUrl } : item)
      })
    }
  }

. После нажатия на кнопку Сохранить, я хотел бы загрузить изображение на s3, сохранив файл в Облако, так что пользователи смогут видеть приложение, когда они открывают его. Здесь, когда я регистрирую состояние items [0] .imageUrl , он отображает ссылку s3.

uploadImage = () => {
    let file = this.state.file;
   let config = this.state.config;
    RNS3.put(file, config)
      .then((response) => {
        console.log(response.headers.Location);
        this.setState({
          items: this.state.items.map((item, i) =>
            i == 0 ?
              { ...item, imageUrl: response.headers.Location } : item)
        })
        console.log('This is the state of items[0].imageUri ' + this.state.items[0].imageUrl)
      })
  }

Итак, здесь я решил сначала загрузить изображение в s3 и установите состояние items [0] .imageUrl для ссылки. затем установите значение params как imageUrl, затем обновите WebAPI, вызвав updateProfileData (params). Проблема, с которой я сейчас сталкиваюсь, заключается в том, что когда я нажимаю «Сохранить», на моем экране появляется предупреждение, которое показывает, что состояние items [0] .imageUrl является локальным файлом. Только после того, как я снова нажму кнопку Сохранить, в предупреждении будет показано состояние items [0] .imageUrl в качестве ссылки s3.

            <TouchableOpacity style={styles.button}
              onPress={() => {
                this.uploadImage();
                let params = {
                  ImageUrl: this.state.items[0].imageUrl,
                  EmployeeBio: this.state.items[0].employeeBio
                };
                alert('This is params, ' + params.ImageUrl);
                this.updateProfileData(params);
              }}>
              <View>
                <Text style={styles.text}>Save</Text>
              </View>
            </TouchableOpacity>

Моя команда и я не можем решить эту проблему проблема ... Спасибо за помощь!

1 Ответ

1 голос
/ 22 января 2020

Проблема в том, что вы делаете вещи в синхронном потоке JS, когда setState является асинхронной функцией. Чтобы решить эту проблему, используйте аргумент обратного вызова в функции setState (второй переданный аргумент, который будет выполнен после установки состояния) и вместо этого выполните свой код updateProfileData.

См. Здесь для объяснения - https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296

Итак, чтобы решить вашу проблему, вы должны сделать что-то вроде этого:

Компонент

<TouchableOpacity style={styles.button}
    onPress={() => this.uploadImage()}>
   <View>
        <Text style={styles.text}>Save</Text>
   </View>
</TouchableOpacity>

uploadImage

uploadImage = () => {
    let file = this.state.file;
   let config = this.state.config;
    RNS3.put(file, config)
      .then((response) => {
        console.log(response.headers.Location);
        this.setState({
          items: this.state.items.map((item, i) =>
            i == 0 ?
              { ...item, imageUrl: response.headers.Location } : item)
        },
        // This is your callback
        () => {
            let params = {
                  ImageUrl: this.state.items[0].imageUrl,
                  EmployeeBio: this.state.items[0].employeeBio
                };
            alert('This is params, ' + params.ImageUrl);
            this.updateProfileData(params);
        })
      })
  }
...