首页 > 解决方案 > 图片上传无法在图片位置显示

问题描述

我正在 react-native expo 上开发一个应用程序,并且我创建了一个用户注册,用户可以在其中上传要在用户个人资料上显示的照片,效果很好,但现在我正在尝试为注册时设置的用户信息,我可以在个人资料上显示用户的所有字段,但也许我缺少更新的内容,当我尝试获取新图像时,它没有被显示,希望如此,其他人可以看到我无法显示和更新这些字段的内容。此外,在我尝试更新用户信息之后,还有一个黄色的早晨错误:

[Unhandled promise rejection: FirebaseError: Function CollectionReference.doc() requires its first argument to be of type non-empty string, but it was: undefined]

这是 Register.js 代码:

import { StatusBar } from 'expo-status-bar';
import Fire from '../../Fire';
import React from 'react';
import { Image, StyleSheet, Text, View } from 'react-native';
import { TextInput, TouchableOpacity } from 'react-native-gesture-handler';
import { Ionicons } from 'react-native-vector-icons';
import UserPermissions from '../../utilities/UserPermissions';
import * as ImagePicker from 'expo-image-picker';

export default class RegisterScreen extends React.Component {
  static navigationOptions = {
    headerShown: false
  };

  state = {
    user: {
      name: '',
      state: '',
      city: '',
      email: '',
      password: '',
      confirmPassword: '',
      profilePhotoUrl: null
    },
    errorMessage: null,
  };

  handlePickProfilePhoto = async () => {
    UserPermissions.getMediaGalleryPermission();

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

    if (!result.cancelled) {
      this.setState({ user: { ...this.state.user, profilePhotoUrl: result.uri } })
    };
  };

  handleSignUp = () => {
    Fire.shared.createUser(this.state.user);
  };

  render() {
    if (!this.state.user.password === this.state.user.confirmPassword) {
      alert("Passwords don't match");
      return;
    } else if (this.state.user.name === '' || this.state.user.state === '' ||
      this.state.user.city === '' || this.state.user.email === '' ||
      this.state.user.password === '' || this.state.user.confirmPassword === '' ) {
        alert("All fields must be filled up");
        return;
    };

    return (
      <View style={styles.container}>
      <StatusBar barStyle='light-content' />

      <View
        style={{  top: 5, alignItems: 'center', width: '100%' }}>
      <Text style={styles.greating}>
        {'Welcome aboard.\nSign up to get startd'}
      </Text>
      <TouchableOpacity style={styles.profilePhotoPlaceholder} 
        onPress={this.handlePickProfilePhoto}>
      <Image
        source={{ uri: this.state.user.profilePhotoUrl }}
        style={styles.profilePhoto}
      />
        <Ionicons
          name='ios-add-circle-outline'
          size={150} color='#fff'
          style={{ marginTop: 1, marginLeft: -10 }}
        />
      </TouchableOpacity>
      </View>


        <View style={styles.errorMessage}>
          {this.state.errorMessage && <Text style={styles.errorMessage}>
            {this.state.errorMessage}
          </Text>}
        </View>

        <View style={styles.form}>
          <View style={{ marginTop: 5 }}>
            <Text style={styles.inputTitle}>Full Name</Text>
            <TextInput
              style={styles.input}
              autoCapitalize='none'
              onChangeText={name => this.setState({ user: {...this.state.user, name} })}
              value={this.state.user.name}
            />
          </View>

          <View style={{ marginTop: 5 }}>
            <Text style={styles.inputTitle}>State of residence</Text>
            <TextInput
              style={styles.input}
              autoCapitalize='none'
              onChangeText={state => this.setState({ user: {...this.state.user, state} })}
              value={this.state.user.state}
            />
          </View>

          <View style={{ marginTop: 5 }}>
            <Text style={styles.inputTitle}>City of residence</Text>
            <TextInput
              style={styles.input}
              autoCapitalize='none'
              onChangeText={city => this.setState({ user: {...this.state.user, city} })}
              value={this.state.user.city}
            />
          </View>

          <View style={{ marginTop: 5 }}>
            <Text style={styles.inputTitle}>Email Address</Text>
            <TextInput
              style={styles.input}
              autoCapitalize='none'
              onChangeText={email => 
                this.setState({ user: {...this.state.user, email} })}
              value={this.state.user.email}
            />
          </View>

          <View style={{ marginTop: 5 }}>
            <Text style={styles.inputTitle}>Password</Text>
            <TextInput
              style={styles.input}
              autoCapitalize='none'
              secureTextEntry={true}
              onChangeText={password =>
                this.setState({ user: {...this.state.user, password} })}
              value={this.state.user.password}
            />
          </View>

          <View style={{ marginTop: 5 }}>
            <Text style={styles.inputTitle}>Confirm Password</Text>
            <TextInput
              style={styles.input}
              autoCapitalize='none'
              secureTextEntry={true}
              onChangeText={confimrPassword =>
                this.setState({ user: {...this.state.user, confimrPassword} })}
              value={this.state.user.confimrPassword}
            />
          </View>
          
        </View>

        <TouchableOpacity style={styles.button} onPress={this.handleSignUp}>
          <Text style={{ color: '#fff', fontWeight: '500' }}>Sign up</Text>
        </TouchableOpacity>

        <TouchableOpacity style={{ alignSelf: 'center', }}>
          <Text
            style={{ color: '#fff', fontSize: 13 }}
            onPress={() => this.props.navigation.navigate('Login')}
          >
            Already Begrato? <Text style={{ color: '#ff2222', fontWeight: '500' }}>
              Login
            </Text>
          </Text>
        </TouchableOpacity>
      </View>
    );
  };
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#263237',
  },
  greating: {
    color: '#ffffffdd',
    marginTop: 6,
    fontSize: 18,
    fontWeight: '400',
    textAlign: 'center'
  },
  errorMessage: {
    color: '#ff222266',
    height: 72,
    alignItems: 'center',
    justifyContent: 'center',
    marginHorizontal: 30
  },
  error: {
    color: '#e9446a',
    fontSize: 13,
    fontWeight: '600',
    textAlign: 'center',
  },
  form: {
    marginBottom: 48,
    marginHorizontal: 30,
  },
  inputTitle: {
    color: '#156cc5',
    fontSize: 10,
    textTransform: 'uppercase',
  },
  input: {
    borderBottomColor: '#ff2222',
    borderBottomWidth: StyleSheet.hairlineWidth,
    height: 25,
    fontSize: 15,
    color: '#7cdcfe'
  },
  button: {
    marginBottom: 25,
    marginHorizontal: 30,
    backgroundColor: '#e9446a',
    borderRadius: 4,
    height: 52,
    alignItems: 'center',
    justifyContent: 'center',
  },
  back: {
    top: -10,
    position: 'relative',
    left: 10
  },
  profilePhoto: {
    position: 'absolute',
    width: 120,
    height: 120,
    borderRadius: 50,
  },
  profilePhotoPlaceholder: {
    width: 120,
    height: 120,
    backgroundColor: '#e1e2e6',
    borderRadius: 50,
    marginTop: 10,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

这是我正在处理的 Profile.js 代码:

import React, { useState, useEffect } from 'react';
import {
  Button,
  Image,
  Text,
  View,
  FlatList,
  StyleSheet,
  Modal,
  TextInput } from 'react-native';
import styled from 'styled-components';
import * as ImagePicker from 'expo-image-picker';
import UserPermissions from '../../utilities/UserPermissions';
import { Feather } from 'react-native-vector-icons';

import firebase from 'firebase';
require('firebase/firestore');
import { connect } from 'react-redux';

function Profile(props) {
  const [userPosts, setUserPosts] = useState([]);
  const [user, setUser] = useState(null);
  const [open, setOpen] = useState(false);
  const [hasMediaLibraryPermission, setHasMediaLibraryPermission] = useState(null);
  const [profilePhotoUrl, setProfilePhotoUrl] = useState(user?.profilePhotoUrl);
  const [name, setName] = useState(user?.name);
  const [state, setState] = useState(user?.state);
  const [city, setCity] = useState(user?.city);
  const [email, setEmail] = useState(user?.email);

useEffect(() => {
  const { currentUser, posts } = props;
  (async () => {
    const mediaLibraryStatus = await ImagePicker.requestMediaLibraryPermissionsAsync();
    setHasMediaLibraryPermission(mediaLibraryStatus.status === 'granted');
  })();

  if (props.route.params.uid === firebase.auth().currentUser.uid) {
    setUser(currentUser)
    setUserPosts(posts)
  } else {
      firebase.firestore()
        .collection('users')
        .doc(props.route.params.uid)
        .get()
        .then((snapshot) => {
          if (snapshot.exists) {
              setUser(snapshot.data());
          }
          else {
              console.log('does not exist')
          }
        })
      firebase.firestore()
        .collection('posts')
        .doc(props.route.params.uid)
        .collection('userPosts')
        .orderBy('creation', 'desc')
        .get()
        .then((snapshot) => {
            let posts = snapshot.docs.map(doc => {
                const data = doc.data();
                const id = doc.id;
                return { id, ...data }
            })
            setUserPosts(posts)
        });
  };

  //content deleted

}, [props.route.params.uid]);
  // create new upload functions
  async function updateProfile(){
    if(name === '' || state === '' || city === ''){
      return;
    }

    await firebase.firestore().collection('users')
    .doc(user.uid).update({
      name: name,
      state: state,
      city: city,
      profilePhotoUrl: profilePhotoUrl
    })

    //Search for all posts from user
    const postDocs = await firebase.firestore().collection('posts')
    .where('userId', '==', user.uid ).get();

    //Search and update names of the user posts
    postDocs.forEach( async doc => {
      await firebase.firestore().collection('posts').doc(doc.id).update({
        name: name,
        state: state,
        city: city,
      })
    });

    let data = {
      uid: user.uid,
      name: name,
      state: state,
      city: city,
      profilePhotoUrl: profilePhotoUrl,
      email: user.email,
    };

    setUser(data);
    storageUser(data);
    setOpen(false);
  };

  async function handlePickProfilePhoto() {
    UserPermissions.getMediaGalleryPermission();

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

    if (!result.cancelled) {
      setProfilePhotoUrl({ user: {...user, profilePhotoUrl: result.uri} });
    };

    setProfilePhotoUrl(result);
  };

  // Image upload

const uploadFile = () => {
  const options = {
    noData: true,
    mediaType: 'photo'
  };

  ImagePicker.launchImageLibrary(options, response => {
    if(response.didCancel){
      console.log('CANCELOU O MODAL.');
    }else if(response.error){
      console.log('Parece que deu algum erro: ' + response.error);
    }else{

      uploadFileFirebase(response);
      setUrl(response.uri);

    }

  })

}


const getFileLocalPath = response => {
  const { path, uri } = response;
  return Platform.OS === 'android' ? path : uri;
};

const uploadFileFirebase = async response => {
  const fileSource = getFileLocalPath(response);
  const storageRef = storage().ref('users').child(user?.uid);
  return await storageRef.putFile(fileSource)
};

  const onLogout = () => {
      firebase.auth().signOut();
  };

  if (user === null) {
      return <View />
  }
  return (
    <View style={styles.container}>

      <View style={{ alignItems: 'center' }}>
        <View style={styles.profilePhotoContainer}>
        {
          user.profilePhotoUrl ?
        (
          <UploadButton>
            <Text style={styles.uploadText}>+</Text>
            <Image style={styles.profilePhoto} source={{ uri: user.profilePhotoUrl }} />
          </UploadButton>
        ) :
        (
          <Image style={styles.profilePhoto}
          source={require('../../assets/defaultProfilePhoto.jpg')}
          />
        )
        }
        </View>
      </View>
      
      <View style={styles.containerInfo}>
        <Text>Usuário: {user?.name}</Text>
        <Text>Estado: {user?.state}</Text>
        <Text>Usuário: {user?.city}</Text>
        <Text>E-mail: {user?.email}</Text>
        
        <View style={{ alignItems: 'center', marginBottom: 10, }}>
          <ButtonStyled bg='#428cfd' onPress={() => setOpen(true)}>
            <ButtonText color='#fff'>Update Profile</ButtonText>
          </ButtonStyled>
        </View>

          <Modal visible={open} animationType="slide" transparent={true}>
            <View style={styles.modalContainer}>
            
              <View style={{ marginTop: 5, marginBottom: 10 }}>
                <Button
                  title='Pick Image From Gallery'
                  onPress={() => handlePickProfilePhoto()}
                />
                <Button
                  title='Save'
                  onPress={uploadFile}
                />
              </View>

              <ButtonBack onPress={() => setOpen(false)}>
                <Feather
                  name="arrow-left"
                  size={22}
                  color="#121212"
                />
                <ButtonText color="#121212" >Voltar</ButtonText>
              </ButtonBack>

              <TextInput
                placeholder={user?.name}
                value={name}
                onChangeText={(text) => setName(text)}
              />
              <TextInput
                placeholder={user?.state}
                value={state}
                onChangeText={(text) => setState(text)}
              />
              <TextInput
                placeholder={user?.city}
                value={city}
                onChangeText={(text) => setCity(text)}
              />
              <TextInput
                placeholder={user?.email}
                value={email}
                onChangeText={(text) => setEmail(text)}
              />

              <ButtonStyled bg="#428cfd"  onPress={updateProfile}>
                <ButtonText color="#f1f1f1">Atualizar</ButtonText>
              </ButtonStyled>
            </View>
          </Modal>

        <Button
            title='Logout'
            onPress={() => onLogout()}
        />
      </View>

      <View style={styles.containerGallery}>
        <FlatList
            numColumns={3}
            horizontal={false}
            data={userPosts}
            renderItem={({ item }) => (
              <View
                style={styles.containerImage}>

                <Image
                    style={styles.image}
                    source={{ uri: item.downloadURL }} // it comes from posts
                />
              </View>
            )}
        />
      </View>
    </View>
  );
};

const ButtonStyled = styled.TouchableOpacity`
  margin-top: 12px;
  align-items: center;
  justify-content: center;
  background-color: ${props => props.bg};
  width: 80%;
  height: 45px;
  border-radius: 5px;
`;

const ButtonText = styled.Text`
  font-size: 20px;
  color: ${props => props.color};
  font-style:  italic;
`;
const ButtonBack = styled.TouchableOpacity`
  position: absolute;
  top: 18px;
  left: 25px;
  flex-direction: row;
  align-items: center;
`;

const UploadButton = styled.TouchableOpacity`
  background-color: #fff;
  width: 165px;
  height: 165px;
  border-radius: 90px;
  justify-content: center;
  align-items: center;
  z-index: 5;
`;

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    containerInfo: {
        margin: 20
    },
    containerGallery: {
        flex: 1
    },
    containerImage: {
        flex: 1 / 3

    },
    image: {
        flex: 1,
        aspectRatio: 1 / 1
    },
    cameraContainer: {
      flex: 1,
      flexDirection: 'row'
    },
    fixedRatio: {
      flex: 1,
      aspectRatio: 1
    },
    modalContainer: {
      width: '100%',
      height: '70%',
      backgroundColor: '#FFF',
      justifyContent: 'center',
      alignItems: 'center',
      position: 'absolute',
      bottom: 0,
    },
    input: {
      width: '90%',
      height: 50,
      backgroundColor: '#DDD',
      borderRadius: 10,
      padding: 10,
      fontSize: 20,
      textAlign: 'center',
    },
    profilePhoto: {
      width: 160,
      height: 160,
      borderRadius: 80,
    },
    profilePhotoContainer: {
      alignItems: 'center',
      marginTop: '5%',
      shadowOpacity: 0.8,
      shadowRadius: 30,
      shadowColor: '#222'
    },
    errorMessage: {
      color: '#ff222266',
      height: 72,
      alignItems: 'center',
      justifyContent: 'center',
      marginHorizontal: 30
    },
    uploadText: {
      zIndex: 1,
      position: 'absolute',
      fontSize: 55,
      color: '#ff8000',
      opacity: 0.4
    },
})
const mapStateToProps = (store) => ({
    currentUser: store.userState.currentUser,
    posts: store.userState.posts
})
export default connect(mapStateToProps, null)(Profile);

我不知道我还应该尝试更新这些字段,那里

标签: react-nativeuploadexpoimagepicker

解决方案


推荐阅读