how can I access data from array inside array - react-native

I need to access an image inside 2 arrays, but I have an error to do a map inside another one any suggestions?
all data printed successfully but I need to access an image which is an array inside another array
I need to access an image inside 2 arrays, but I have an error to do a map inside another one any suggestions?
here is the code
`
import { StyleSheet, Text, View, FlatList, Image,Dimensions } from 'react-native'
import React, { useEffect, useState } from 'react'
import Artist from '../components/Artist'
import SearchHeader from '../components/SearchHeader';
import { useNavigation, useRoute } from "#react-navigation/native";
import { SafeAreaView } from 'react-native-safe-area-context';
import axios from 'axios';
import { Artistfu } from '../services.js/services';
const ArtistSearch = () => {
const route = useRoute()
let token = route.params.token
const navigation = useNavigation();
const [artistt, setArtistt] = useState([]);
const [error, setError] = useState('');
const [images, setImages] = useState([])
useEffect(() => {
Artistfu().then(artists => {
setArtistt(artists)
setImages(artists[0].images)
}).catch(err => {
setError(err);
});
}, []);
console.log(artistt)
return (
<View>
{
artistt.map((ar, i) => (
<View
key={i}
>
<Text>{ar.followers.total}</Text>
{images.map((img)=>(
<Image source={{ uri: img.images.url }} style={{ height: 210, width: Dimensions.get('window').width - 40, resizeMode: 'cover' }} />
))}
<Text >{ar.name}</Text>
<Text>{ar.popularity}</Text>
</View>
))
}
</View>
)
}
export default ArtistSearch
const styles = StyleSheet.create({
})
services file :
import axios from 'axios';
const apiUrl = 'https://api.spotify.com'
const token = 'query=remaster%2520track%3ADoxy%2520artist%3AMiles%2520Davis&type=artist&market=ES&locale=en-US%2Cen%3Bq%3D0.9&offset=5&limit=10'
export const Artistfu = async () => {
const resp = await axios.get(`${apiUrl}/v1/search?${token}`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: "Bearer " + token,
},
})
return resp.data.artists.items
};
`
and the data look like json:
`
{
"artists": {
"href": "https://api.spotify.com/v1/search?query=remaster%2520track%3ADoxy%2520artist%3AMiles%2520Davis&type=artist&market=ES&locale=en-US%2Cen%3Bq%3D0.9&offset=5&limit=10",
"items": [
{
"external_urls": {
"spotify": "https://open.spotify.com/artist/1MVFEpYdHtdV3k8Bgs79Pl"
},
"followers": {
"href": null,
"total": 404
},
"genres": [],
"href": "https://api.spotify.com/v1/artists/1MVFEpYdHtdV3k8Bgs79Pl",
"id": "1MVFEpYdHtdV3k8Bgs79Pl",
"images": [
{
"height": 640,
"url": "https://i.scdn.co/image/ab6761610000e5ebd1578a57ff89ac9aeed23863",
"width": 640
},
{
"height": 320,
"url": "https://i.scdn.co/image/ab67616100005174d1578a57ff89ac9aeed23863",
"width": 320
},
{
"height": 160,
"url": "https://i.scdn.co/image/ab6761610000f178d1578a57ff89ac9aeed23863",
"width": 160
}
],
"name": "DOXY",
"popularity": 14,
"type": "artist",
"uri": "spotify:artist:1MVFEpYdHtdV3k8Bgs79Pl"
},
]
}
}
`

The below should work
artists.items[0].images

Related

Typescript:react-native-deck-swiper undefined is not an object (evaluation'card.image')

I got stuck in a super weird issue ...
I am using a third party library : react-native-deck-swiper ;
And it was able to render the users'image ,however ,after feel secds ,it occurs this error : undefined is not an object(evaluating'card.image');Could you please take a look my code ? Thank you so much in advance !!
I had installed :
yarn add react-native-deck-swiper
Here , I defined my Card Component :
import { StyleSheet, View,Image } from 'react-native'
import React from 'react'
interface UserProps{
card :{
image : string,
}
}
const Card = ({card}:UserProps) => {
return (
<View style={styles.Container}>
<Image source={{uri:card.image}} style={styles.userImage}/>
</View>
)
}
export default Card
const styles = StyleSheet.create({
Container :{
flex:0.6,
backgroundColor:'white',
flexDirection:'column',
borderRadius:10,
elevation:10,
alignItems:'center',
paddingHorizontal:10,
},
userImage:{
width:80,
height:80,
borderRadius:80,
marginTop:30,
},
})
And I some of my users image list :
export default{
"code": 0,
"data": [
{
"_id": "1",
"image": "https://i.pinimg.com/564x/49/5e/38/495e3854551b7ecd87631b682b77b31e.jpg",
"userName": "hei you ",
"gender": "female",
"birthday": "1994-4-13",
},
{
"_id": "2",
"image": "https://i.pinimg.com/564x/b5/6f/97/b56f97ac0b8f521586d3aee555070162.jpg",
"userName": "Mo Mo",
"gender": "female",
"birthday": "1995-4-13",
},
{
"_id": "3",
"image": "https://i.pinimg.com/564x/d9/71/8c/d9718c2e22cf0495361c55034941ddf5.jpg",
"userName": "Jack",
"gender": "male",
"birthday": "1991-4-13",
},
{
"_id": "4",
"image": "https://i.pinimg.com/564x/d1/94/8d/d1948d39ef9d38972700592a1673a68c.jpg",
"userName": "Peter",
"gender": "male",
"birthday": "1990-4-13",
},
{
"_id": "5",
"image": "https://i.pinimg.com/564x/a8/15/66/a815661117cdec309b45fe9f8cdf1d70.jpg",
"userName": "La La",
"gender": "female",
"birthday": "1998-4-13",
},
],
"msg": "success"
}
And I used it in my HomeScreen :
import { Image, ImageBackground, StatusBar, StyleSheet, Text, View } from 'react-native';
import React,{useState,useEffect}from 'react';
import Swiper from 'react-native-deck-swiper';
import HomeUsers from '../../services/HomeUsers';
import Card from '../../components/Card';
function HomeScreen(prop:any) {
const {navigation} = prop;
const [unreadMsgReceive,setUnreadMsgRceive] = useState(0);
const [unreadMsgGive,setUnreadMsgGive] =useState(0);
const [data,setData] = useState([]);
const [index,setIndex] =useState(0);
useEffect(()=>{
setData(HomeUsers.data);
},[]);
const onSwiped = () =>{
setIndex(index +1);
}
const netInfo = useNetInfo();
return (
<ImageBackground style={styles.bg} source={require('../../assets/images/yellow_bg.png')}>
{/**Swiper Cards 'rgba(52, 52, 52, 0)'*/}
<View style={styles.cardsSwipperContainer}>
<Swiper
cards ={data}
cardIndex ={index}
stackSize={4}
stackScale={10}
stackSeparation={14}
infinite ={true}
cardVerticalMargin ={10}
backgroundColor ={'transparent'}
onSwiped = {onSwiped}
renderCard = {card =><Card card={card}/>}
/>
</View>
</ImageBackground>
);
}
export default HomeScreen;
const styles = StyleSheet.create({
bg:{
flex :1,
resizeMode:"cover",
flexDirection:'column',
},
cardsSwipperContainer:{
flex:0.8
},
});
You passing card as prop <Card card={card}/> but define no card. but cards. may react native only notices it after a few seconds.
I have finally solved the problem ,only need to pass the data in direactly ,no need state :
<View style={styles.cardsSwipperContainer}>
<Swiper
cards ={HomeUsers.data}
cardIndex ={index}
stackSize={4}
stackScale={10}
stackSeparation={14}
cardVerticalMargin ={10}
backgroundColor ={'transparent'}
onSwiped = {onSwiped}
infinite ={true}
renderCard = {card =><Card card={card}/>}
/>
</View>

How to pass data which is not relevant to render through Flatlist?

I create Flatlist as below.
export default function Comments({ route }) {
const renderComment = ({ item: comments }) => {
return <CommentRow {...comments} />;
};
return (
<Container>
<CommentBox>
<FlatList
keyboardDismissMode={true}
showsVerticalScrollIndicator={false}
data={route.params.comments}
keyExtractor={(comment) => "" + comment.id}
renderItem={renderComment}
/>
</CommentBox>
</Container>
);
}
rendered data set seems like below:
Object {
"key": "Comments-uxnCZKk0KvTmpppxkM8IF",
"name": "Comments",
"params": Object {
"comments": Array [
Object {
"__typename": "Comment",
"createdAt": "1642680008811",
"id": 1,
"isMine": false,
"payload": "등산 너무 좋았겠네~~",
"user": Object {
"__typename": "User",
"avatar": "https://chungchunonuploads.s3.ap-northeast-2.amazonaws.com/avatars/4-1642681358399-%E1%84%80%E1%85%B5%E1%86%B7%E1%84%8C%E1%85%A5%E1%86%BC%E1%84%92%E1%85%A9.png",
"username": "김정호",
},
},
Object {
"__typename": "Comment",
"createdAt": "1642680037676",
"id": 3,
"isMine": false,
"payload": "다음주에 그 산으로 가자 우리도~~",
"user": Object {
"__typename": "User",
"avatar": "https://chungchunonuploads.s3.ap-northeast-2.amazonaws.com/avatars/4-1642681358399-%E1%84%80%E1%85%B5%E1%86%B7%E1%84%8C%E1%85%A5%E1%86%BC%E1%84%92%E1%85%A9.png",
"username": "김정호",
},
},
],
"photoId": 1,
},
"path": undefined,
}
So It successfully works.
I return it to <CommentRow> Screen with this data set.
But I need to pass another data which is photoId.
this photoId exists in this screen but not in CommentRow Screen.
And comments data set doesn't have this photoId information. So I need separately send it to CommentRow Screen with {...comments} data.
But How can I send it through Flatlist?
I tried to make another object as combining comments object with photoId. But It failed :(
or Should I just bring photoId information in CommentRow screen as not passing through Flatlist?
If you need more explanation about my code, I can answer on real time.
please help me.
CommentRow Screen.
PhotoId is used in cache.modify part since it is needed to update my cache.
export default function CommentRow({
id,
user,
payload,
isMine,
createdAt,
updatedAt,
commentNumber,
}) {
const navigation = useNavigation();
const createdDate = new Date(+createdAt);
const date = createdDate.toISOString().substring(0, 10);
const updateDeleteComment = (cache, result) => {
const {
data: {
deleteComment: { ok, error },
},
} = result;
if (ok) {
cache.evict({ id: `Comment:${id}` });
cache.modify({
id: `Photo:${photoId}`,
fields: {
comments(prev) {
return [...prev, newCacheComment];
},
comments(prev) {
return prev +1;
}
}
})
}
};
const [deleteCommentMutation] = useMutation(DELETE_COMMENT_MUTATION, {
variables: {
id,
},
update: updateDeleteComment,
});
const onDeleteClick = () => {
deleteCommentMutation();
};
return (
<Container>
<CommentContainer>
<UserImage source={{ uri: user.avatar }} />
<TextBox>
<Header>
<Username>{user.username}</Username>
<CreatedTime>{date}</CreatedTime>
</Header>
<CommentText>{payload}</CommentText>
</TextBox>
</CommentContainer>
{isMine ? (
<WriteContainer>
<TouchableOpacity>
<WriteComment>수정</WriteComment>
</TouchableOpacity>
<TouchableOpacity onPress={onDeleteClick}>
<WriteComment>삭제</WriteComment>
</TouchableOpacity>
</WriteContainer>
) : null}
</Container>
);
}
Change renderComment as
const renderComment = ({ item: comments }) => {
const photoIdobj = { photoId: `${route.params.photoId}` };
const passedComments = { ...comments, ...photoIdobj };
return <CommentRow {...passedComments} />;
};
and call photoId from CommentRow like
export default function CommentRow({
id,
user,
payload,
isMine,
createdAt,
updatedAt,
commentNumber,
photoId
})
I got an idea from #Thanhal's answer.
I made the new object as combining comments and photoId as below.
then it works.
const renderComment = ({ item: comments }) => {
const photoIdobj = { photoId: `${route.params.photoId}` };
const passedComments = { ...comments, ...photoIdobj };
return <CommentRow {...passedComments} />;
};
return (

Unable to get information on a Reducer using Redux

I have a question with a Reducer, the problem is that I'm used to get data from an API which brings just Key Value Pairs something like:
{
"-MObNVR5e180MfhvtbRY": {
"altura": "179 cm",
"apellido": "Cuéllar De León",
"edad": 31,
"fecha_nacimiento": "20/10/1989",
"imagen": "https://firebasestorage.googleapis.com/v0/b/alianzafc2021.appspot.com/o/yimmi%20cuellar.jpg?alt=media&token=144fa106-eabb-40c8-83b6-2e4b45034eda",
"iso_code": "SV",
"lugar_nacimiento": "San Julián",
"nacionalidad": "El Salvador",
"nombre_completo": "Yimmy Rodrigo Cuéllar De León",
"nombre_corto": "Yimmy Cuéllar",
"nombres": "Yimmy Rodrigo",
"numero": 1,
"pais": "El Salvador",
"peso": "66 kg",
"player_id": 108911,
"posicion": "Portero"
},
}
Now I need to get the data from an API that has Arrays within the Array like this:
{
"api": {
"results": 13,
"players": [
{
"player_id": 79308,
"player_name": "Felipe Ponce Ramírez",
"firstname": "Felipe",
"lastname": "Ponce Ramírez",
"number": null,
"position": "Midfielder",
"age": 32,
"birth_date": "29/03/1988",
"birth_place": "Ciudad Lerdo",
"birth_country": "Mexico",
"nationality": "Mexico",
"height": "177 cm",
"weight": "67 kg",
"injured": null,
"rating": null,
"team_id": 4299,
"team_name": "Alianza",
"league_id": 2979,
"league": "Primera Division",
"season": "2020-2021",
"captain": 0,
"shots": {
"total": 0,
"on": 0
},
"goals": {
"total": 4,
"conceded": 0,
"assists": 0,
"saves": 0
},
"passes": {
"total": 0,
"key": 0,
"accuracy": 0
},
"tackles": {
"total": 0,
"blocks": 0,
"interceptions": 0
},
"duels": {
"total": 0,
"won": 0
},
"dribbles": {
"attempts": 0,
"success": 0
},
"fouls": {
"drawn": 0,
"committed": 0
},
"cards": {
"yellow": 2,
"yellowred": 0,
"red": 0
},
"penalty": {
"won": 0,
"commited": 0,
"success": 0,
"missed": 0,
"saved": 0
},
"games": {
"appearences": 6,
"minutes_played": 194,
"lineups": 2
},
"substitutes": {
"in": 4,
"out": 2,
"bench": 0
}
},
}
Someone told me that I will need to create a Data Model for each SubArray so I did and I used it in my Action File like this:
export const fetchEstadistica = player_id => {
return async (dispatch) => {
//any async code here!!!
try {
const response = await fetch(
`https://api-football-v1.p.rapidapi.com/v2/players/player/${player_id}.json`,
{
method: 'GET',
headers: new Headers({
'x-rapidapi-key': //Here Goes My API Key which I keep for Security Reasons,
'x-rapidapi-host': 'api-football-v1.p.rapidapi.com',
'useQueryString': 'true'
})
}
);
if (!response.ok) {
throw new Error('Algo salio Mal!');
}
const resData = await response.json();
const loadesApiResult = [];
console.log(resData);
//Arrays de la Estadistica del Jugador
const loadedEstadistica = [];
const loadedCards = [];
const loadedGoals = [];
const loadedGames = [];
for (const key in resData) {
loadesApiResult.push(
new ResultadoEstadistica(
key,
resData[key].results,
resData[key].players
)
);
}
const apiData = loadesApiResult.players;
for (const key in apiData){
loadedEstadistica.push(
new PlayerEstadistica (
apiData[key].player_id,
apiData[key].player_name,
apiData[key].firstname,
apiData[key].lastname,
apiData[key].number,
apiData[key].position,
apiData[key].age,
apiData[key].birth_date,
apiData[key].birth_place,
apiData[key].birth_country,
apiData[key].nationality,
apiData[key].height,
apiData[key].weight,
apiData[key].injured,
apiData[key].rating,
apiData[key].team_id,
apiData[key].team_name,
apiData[key].league_id,
apiData[key].league,
apiData[key].season,
apiData[key].captain,
apiData[key].shots,
apiData[key].goals,
apiData[key].passes,
apiData[key].duels,
apiData[key].dribbles,
apiData[key].fouls,
apiData[key].cards,
apiData[key].penalty,
apiData[key].games,
apiData[key].substitutes,
)
);
}
const playerDataGames = loadedEstadistica.games;
for (const key in playerDataGames){
loadedGames.push(
new Games(
playerDataGames[key].apperences,
playerDataGames[key].minutes_played,
playerDataGames[key].lineups
)
);
};
const playerDataGoals = loadedEstadistica.goals;
for (const key in playerDataGoals){
loadedGoals.push(
new Goals(
playerDataGoals[key].total,
playerDataGoals[key].conceded,
playerDataGoals[key].assists,
playerDataGoals[key].saves
)
);
};
const playerDataCards = loadedEstadistica.cards;
for (const key in playerDataCards){
loadedCards.push(
new Cards(
playerDataCards[key].yellow,
playerDataCards[key].yellowred,
playerDataCards[key].red
)
);
};
dispatch({ type: SET_ESTADISTICA, estadistica: loadedEstadistica, goles: loadedGoals, juegos: loadedGames, tarjetas: loadedCards });
} catch (err) {
throw err;
}
};
};
Then I get this into my Readucer with the Type:
import { SET_JUGADORES, SET_ESTADISTICA } from "../actions/jugadores";
const initialState = {
availablePlayers: [],
estadistica: [],
playerGoals: [],
playerCards: [],
playerGames: [],
}
export default (state = initialState, action) => {
switch (action.type) {
case SET_JUGADORES:
return {
availablePlayers: action.players,
};
case SET_ESTADISTICA:
return{
estadistica: estadistica,
// playerGoals: action.goles,
// playerCards: action.tarjetas,
// playerGames: action.juegos
};
}
return state;
};
Finally, I go and call the Reducer from:
import React, {useState, useCallback, useEffect} from 'react';
import { ScrollView, Text, Image, StyleSheet, View } from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
const ProductDetailScreen = props => {
const playerId = props.route.params.id;
const estadId = props.route.params.statId;
const selectedPlayer = useSelector(state => state.jugadores.availablePlayers.find(prod => prod.id === playerId));
const [isLoading, setIsLoading] = useState(false);
const [isRefreshing, setIsRefreshing] = useState(false);
const [error, setError] = useState();
const goles = useSelector(state => state.jugadores.estadistica);
const dispatch = useDispatch();
const loadEstad = useCallback (async (estadId) => {
setError(null);
setIsRefreshing(true);
try {
await dispatch(userActions.fetchEstadistica(estadId));
} catch (err){
setError(err.message);
}
setIsRefreshing(false);
}, [dispatch, setIsLoading, setError]);
useEffect(() => {
setIsLoading(true);
loadEstad(estadId).then(() => {
setIsLoading(false);
});
}, [dispatch, loadEstad]);
console.log(estadId);
console.log(goles);
return (
<ScrollView>
<Image style={styles.image} source={{ uri: selectedPlayer.imagen }} />
<View style={styles.dataContainer}>
<Text style={styles.description}>Numero: <Text style={styles.subtitle}>{selectedPlayer.numero}</Text></Text>
<Text style={styles.description}>Nombre Completo: <Text style={styles.subtitle}>{selectedPlayer.nombre_completo}</Text></Text>
<Text style={styles.description}>Posicion: <Text style={styles.subtitle}>{selectedPlayer.posicion}</Text> </Text>
<Text style={styles.description}>Edad: <Text style={styles.subtitle}>{selectedPlayer.edad}</Text></Text>
<Text style={styles.description}>Nacionalidad: <Text style={styles.subtitle}>{selectedPlayer.nacionalidad}</Text></Text>
</View>
</ScrollView>
);
};
export const screenOptions = navData => {
return {
headerTitle: navData.route.params.nombre,
}
};
const styles = StyleSheet.create({
image: {
width: '100%',
height: 300,
},
subtitle: {
fontSize: 16,
textAlign: 'justify',
marginVertical: 20,
fontWeight:'normal',
},
description: {
fontSize: 16,
textAlign: 'center',
marginVertical: 20,
fontWeight: 'bold',
},
dataContainer:{
width: '80%',
alignItems: 'center',
marginHorizontal: 40,
},
actions: {
marginVertical: 10,
alignItems: 'center',
},
});
export default ProductDetailScreen;
However when I go to watch the Terminal I see that when I do the console.log(goles) which receives the slice of the Reducer I get Undefined.
I'm not sure what am I doing Wrong, any ideas?
Kind Regards
Try this
import { SET_JUGADORES, SET_ESTADISTICA } from "../actions/jugadores";
const initialState = {
availablePlayers: [],
estadistica: [],
playerGoals: [],
playerCards: [],
playerGames: [],
}
export default (state = initialState, action) => {
switch (action.type) {
case SET_JUGADORES:
return {
...state,
availablePlayers: action.players,
};
case SET_ESTADISTICA:
return{
...state,
estadistica: state.estadistica,
// playerGoals: action.goles,
// playerCards: action.tarjetas,
// playerGames: action.juegos
};
}
return state;
};

Uploading image to AWS S3

i am a beginner in react native. my problem is, i am trying to send image from camera to aws s3. this is my latest code.
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity, Button, Image } from 'react-native';
import ImagePicker from 'react-native-image-picker';
import { RNS3 } from 'react-native-aws3';
import fs from 'react-native-fs';
import Buffer from 'buffer';
import AWS from 'aws-sdk';
function uploadToS3(image){
const filename = "the_file.jpeg";
const options = {
keyPrefix: "uploads/",
bucket: "this is bucketname",
region: "this is region",
accessKey: "this is access key",
secretKey: "this is secret key",
successActionStatus: 201
}
try{
const s3 = new AWS.S3({accessKeyId: options.accessKey, secretAccessKey:options.secretKey, region:options.region});
var UploadURL;
const params = {Bucket: options.bucket, Key: options.keyPrefix+filename, ContentType: image.type};
s3.getSignedUrl('putObject', params, function (err, url) {
console.log('Your generated pre-signed URL is', url);
UploadURL = url;
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log("ok: ", xhr.response);
alert("success");
} else {
console.log("no: " , xhr.response);
alert("no");
}
}
}
xhr.open('PUT', UploadURL)
xhr.setRequestHeader('Content-Type', image.type)
xhr.send({image})
});
} catch(error){
console.log("err : ",error)
}
}
class HomeScreen extends React.Component {
constructor(props) {
global.currentScreenIndex = 'HomeScreen';
super(props);
this.state = {
resourcePath: {},
requestStatus: {},
employees: {},
response: {},
};
}
cameraLaunch = (id) => {
console.log(id);
let options = {
title: 'Select Picture',
storageOptions: {
skipBackup: true,
path: 'images',
},
base64: true,
maxWidth: 400,
maxHeight: 400
};
ImagePicker.launchCamera(options, (res) => {
//console.log('Response = ', res);
if (res.didCancel) {
console.log('User cancelled image picker');
} else if (res.error) {
console.log('ImagePicker Error: ', res.error);
} else if (res.customButton) {
console.log('User tapped custom button: ', res.customButton);
alert(res.customButton);
} else {
let source = res;
this.setState({
resourcePath: source,
});
uploadToS3(res);
}
});
}
render(){
return (
<View style={{ flex: 1, alignItems: 'center', marginTop: 100 }}>
<Button
onPress={()=>this.cameraLaunch(1)}
title="OpenCamera"
color="#841584"
/>
<Text style={{ alignItems: 'center' }}>
{this.state.resourcePath.uri}
</Text>
<Image source={this.state.resourcePath} />
</View>
);
}
};
export default HomeScreen;
there is nothing wrong with the camera or presigned url generation. if run, there will be the_file.jpeg in "this is bucket name"/uploads/the_file.jpeg, but the problem is, its size is 0 byte. i have tried to send just image.data, but apparently it just make the_file.jpeg become a "txt file" with "jpeg" extension. please help.
ps : i am aware on how insecure this code.
It looks like you missed the purpose of presigned URLs which is to upload objects without the need of AWS credentials. In your example, you are initializing the S3 client using the AWS credential, in that case, you can simply use s3.upload function to upload your file.
I had the same issue and nothing helped. This is what I did.
Make sure you follow the amplify guide for setting up a app. amplify init, amplify add auth, amplify push, and then amplify add storage and then do this.
import Amplify, { Storage } from 'aws-amplify'
import config from './src/aws-exports'
// import awsconfig from './aws-exports';
// Might need to switch line 7 to awsconfig
Amplify.configure(config)
import { StatusBar } from 'expo-status-bar';
import React, { useState, useEffect } from 'react';
import { Button, Image, View, Platform, StyleSheet, Text, TextInput } from 'react-native';
import * as ImagePicker from 'expo-image-picker';
function App() {
const [image, setImage] = useState(null)
const [name, setName] = useState('Evan Erickson')
useEffect(() => {
(async () => {
if (Platform.OS !== 'web') {
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== 'granted') {
alert('Sorry, we need camera roll permissions to make this work!');
}
}
})();
}, []);
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(result)
async function pathToImageFile(data) {
try {
const response = await fetch(data);
const blob = await response.blob();
await Storage.put(`customers/${name}`, blob, {
contentType: 'image/jpeg', // contentType is optional
});
} catch (err) {
console.log('Error uploading file:', err);
}
}
// later
pathToImageFile(result.uri);
}
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button title="Pick an image from camera roll" onPress={pickImage} />
{image && <Image source={{ uri: image }} style={{ width: 200, height: 200 }} />}
<Button title="Upload image" onPress={() => {alert(image)}} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default withAuthenticator(App)

How do I get access to to this.props.navigation if I'm on my RootPage?

I need to pass this.props.navigation to a helper function. However, I'm currently sitting on the root page, which initially creates the stackNavigator. So far I've tried importing Navigator, NavigatorActions and withNavigation from react-navigation and then sending it/them along as a parameter to my helper function, but I keep getting the error message: cannot read property 'state' of undefined.
Here is my RootPage code that is relevant:
/**
* RootPage has the Navigator. So it controls navigation.
*/
import React, { Component } from 'react';
import {
Platform,
BackHandler,
View,
Animated,
StyleSheet,
Image,
TouchableWithoutFeedback,
TouchableOpacity,
Alert
} from 'react-native';
import { connect } from 'react-redux';
import { BoxShadow } from 'react-native-shadow';
import { NavigationActions } from 'react-navigation';
import { vsprintf } from 'sprintf-js';
import RootNavigator from './RootNavigator';
//Test Component
import TestPageFactory from '../TestPage/TestPageFactory';
// Components
import XXBluetoothManager, { XXBluetoothEventEmitter } from '../../nativeComponents/XXBluetooth/XXBluetooth';
import XXText from '../../components/XXText/XXRobotoText';
import XXSyncXXerlay from '../../components/XXSyncXXerlay/XXSyncXXerlay';
// Actions
import { logout } from '../../actions/user';
import { closeSyncModal, toggleRootMenu, openRootMenu, closeRootMenu } from '../../actions/page';
// Utils
import { LAYOUTINFO } from '../../utils/layoutinfo';
import { generateElevationStyle } from '../../utils/util';
import { NavUtils } from '../../utils/navutils';
import { StatusBarManager } from '../../utils/statusbarmanager';
// Config
import { DEVICEINFO } from '../../config';
// Localization
import I18n from '../../localization/i18n';
import { aDeviceHasBeenConnectedFunc } from '../../actions/device';
// Constants
const DEFAULT_PROFILE_IMAGE = require('../../images/profile-image/user.png');
const HEIGHT_RATIO = DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 0.5 : (DEVICEINFO.SCREEN_HEIGHT >= 667 ? (DEVICEINFO.SCREEN_HEIGHT / 667) : 0.7);
class RootPage extends Component {
static getDerivedStateFromProps(nextProps, prevState) {
let shouldLoadingBeVisible = nextProps.pageStatus && nextProps.pageStatus.isUpdateRequested ? true : false;
if (!nextProps.profile && shouldLoadingBeVisible === prevState.loadingVisible) {
return null;
}
return {
profileImage: nextProps.profile && nextProps.profile.profileImage ?
{ uri: nextProps.profile.profileImage } : DEFAULT_PROFILE_IMAGE,
profileName: nextProps.profile && nextProps.profile.profileName ? nextProps.profile.profileName : '',
loadingVisible: shouldLoadingBeVisible,
};
}
constructor(props) {
super(props);
this.routeStatusBarStyle = 'dark-content';
this.state = {
animatedPosition: new Animated.ValueXY(0, 0),
profileImage: DEFAULT_PROFILE_IMAGE,
profileName: '',
deviceAddress: undefined,
isMenuVisible: false,
loggingOut: false,
device: undefined,
};
}
componentDidMount() {
if (Platform.OS === 'android') {
this.initAndroidHardwareBackEvent();
}
// this.initializeBluetooth();
}
componentWillUnmount() {
this.destroyBluetooth();
}
componentDidUpdate(prevProps, prevState) {
if (this.state.loggingOut) {
if (this.props.signinStatus && !this.props.signinStatus.isLoginSuccess) {
this.setState({ loggingOut: false }, () => {
this.onPressMenu('EntryPage');
});
}
}
if (this.props.pageStatus.isMenuVisible != null && prevState.isMenuVisible !== this.props.pageStatus.isMenuVisible) {
this.setState({ isMenuVisible: this.props.pageStatus.isMenuVisible }, () => {
this.onUpdateMenu(this.props.pageStatus.isMenuVisible);
});
}
// console.log('what are the prev state here? ", ', prevState)
/*
NOTE: We need to know when an item has been connected, if an item has not been connected, we should
make the hearing test available
*/
}
render() {
return (
<View style={styles.rootView}>
{this.renderRootMenu()}
<Animated.View style={[styles.animatedView, { left: this.state.animatedPosition.x, top: this.state.animatedPosition.y }]}>
{this.renderXXerlay()}
{this.renderNavigator()}
</Animated.View>
{this.renderSyncXXerlay()}
</View>
);
}
updateStatusBarStyle(pageId) {
let newStatusBarStyle = 'dark-content';
if (pageId === 'EntryPage') {
newStatusBarStyle = 'light-content';
}
if (newStatusBarStyle !== this.routeStatusBarStyle) {
this.routeStatusBarStyle = newStatusBarStyle;
StatusBarManager.setStyle(newStatusBarStyle, false)
}
}
renderRootMenu() {
return (
<View style={styles.menuView}>
{this.renderMenuTopArea()}
{this.renderMenuBottomArea()}
</View>
)
}
renderMenuTopArea() {
if (DEVICEINFO.IS_ANDROID && (Platform.Version === 19 || Platform.Version === 20)) {
return this.renderMenuTopAreaKitKat();
}
return this.renderMenuTopAreaDefault();
}
renderMenuTopAreaDefault() {
return (
<View style={[styles.menuTopArea, generateElevationStyle(1.5)]}>
{this.renderProfileImage()}
</View>
)
}
renderMenuTopAreaKitKat() {
let shadowOptions = {
width: DEVICEINFO.SCREEN_WIDTH,
height: (DEVICEINFO.SCREEN_HEIGHT * 0.35) + 2,
color: '#000',
border: 2,
opacity: 0.05,
radius: 1,
y: -2.5,
};
return (
<BoxShadow setting={shadowOptions}>
<View style={styles.menuTopArea}>
{this.renderProfileImage()}
</View>
</BoxShadow>
)
}
renderMenuBottomArea() {
return (
<View style={styles.menuBottomArea}>
{this.renderMenuContents()}
</View>
)
}
renderMenuContents() {
const menuData = this.generateMenuData();
let renderOutput = [];
for (let i = 0, len = menuData.length; i < len; i++) {
if (this.state.deviceAddress && menuData[i].onlyNotConnected) {
continue;
}
let extraStyle = {};
if (i === 0) {
let extraStyleMarginTop = DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 16 : 26;
extraStyle['marginTop'] = extraStyleMarginTop * LAYOUTINFO.DESIGN_HEIGHT_RATIO;
}
renderOutput.push(
<TouchableOpacity
key={menuData[i].text}
activeOpacity={0.8}
underlayColor='transparent'
onPress={() => { menuData[i].onPressMenu() }}
style={[styles.menuButtonTouch, extraStyle]}>
<View style={styles.menuButtonView}>
<Image
source={menuData[i].icon}
style={[styles.menuIcon]} />
<XXText style={[styles.menuText]}>{menuData[i].text}</XXText>
</View>
</TouchableOpacity>
)
}
return renderOutput;
}
generateMenuData() {
return [
this.generateMenuItem(I18n.t('home'), require('../../images/menu-home.png'), 'HomePage'),
this.generateMenuItem(I18n.t('tutorial'), require('../../images/menu-tutorial.png'), 'SelectTutorialPage'),
this.generateMenuItem(I18n.t('item_list'), require('../../images/menu-add-item.png'), 'itemListPage'),
this.generateMenuItem(I18n.t('report'), require('../../images/menu-report.png'), 'ReportDetailPage'),
this.generateTestPageOnly(I18n.t('hearing_test'), require('../../images/menu-demotest.png')),
this.generateMenuItem(I18n.t('equalizer'), require('../../images/menu-sound.png'), 'SoundPage'),
this.generateMenuItem(I18n.t('support'), require('../../images/menu-support.png'), 'SupportPage'),
this.generateMenuItem(I18n.t('account_settings'), require('../../images/menu-settings.png'), 'SettingsPage'),
{
text: I18n.t('logout'),
icon: require('../../images/menu-logout.png'),
onPressMenu: () => {
Alert.alert(
I18n.t('item'),
I18n.t('logout_confirmation'),
[
{ text: I18n.t('cancel'), onPress: () => { } },
{ text: I18n.t('logout'), onPress: () => { this.onPressLogout() } }
]
)
}
},
];
}
generateTestPageOnly(label, icon) {
let deviceAddress;
let versionData;
// console.log('what is the props here: ', this.props.devices)
function loopThruObject(objectOfDevices) {
for (let [key, value] of Object.entries(objectOfDevices)) {
for (let [newKey, newValue] of Object.entries(value)) {
if (newKey === 'macAddress') {
deviceAddress = newValue;
}
if (newKey === 'version')
versionData = newValue
}
}
return;
}
loopThruObject(this.props.devices)
let currentDevice = this.props.devices[deviceAddress];
let newParams = {
navIndex: 1,
device: currentDevice
};
if (this.props.aDeviceHasBeenConnected === true) {
return {
text: label,
icon: icon,
onPressMenu: () => {
let testPageIdentifier = TestPageFactory.getIdentifier({ isDemo: false, versionData: versionData });
console.log('what is the testPage identifier: ', this.props.navigation)
// NavUtils.push(NavigationActions, testPageIdentifier, { device: currentDevice });
NavigationActions.dispatch({ type: 'Navigation/NAVIGATE', routeName: 'FittingTestPage', params: newParams })
}
}
}
if (this.props.aDeviceHasBeenConnected === false) {
return {
text: 'N/A',
icon: icon,
onPressMenu: () => {
}
}
}
}
generateMenuItem(label, icon, onPressId, onlyNotConnected = false) {
return {
text: label,
icon: icon,
onPressMenu: () => {
this.onPressMenu(onPressId);
},
onlyNotConnected
}
}
renderProfileImage() {
imageSource = this.state.profileImage;
let deviceCount = Object.keys(this.props.devices).length;
let deviceConnectionString = this.generateConnectedString(deviceCount);
return (
<View style={styles.profileImageSubContainer}>
<Image
key={this.state.profileImage.uri}
source={imageSource}
style={styles.profileImage} />
{/* <XXText style={[styles.profileText]} fontWeight='Regular'>{this.state.profileName}</XXText> */}
<XXText style={[styles.deviceText]} fontWeight={'Light'}>{deviceConnectionString}</XXText>
</View>
)
}
generateConnectedString(deviceCount) {
let deviceConnectionString;
if (deviceCount === 1) {
deviceConnectionString = vsprintf(I18n.t('one_item_connected_format_str'), deviceCount.toString());
}
else {
deviceConnectionString = vsprintf(I18n.t('items_connected_format_str'), deviceCount.toString());
}
return deviceConnectionString;
}
renderNavigator() {
return (
<RootNavigator
ref={nav => {
this.navigator = nav;
}}
onNavigationStateChange={(prevState, currentState) => {
this.handleNavSceneChange(prevState, currentState);
}} />
)
}
handleNavSceneChange(prevState, currentState) {
const currentScreen = NavUtils.getCurrentRouteNameFromState(currentState);
this.currentPageId = currentScreen;
this.updateStatusBarStyle(currentScreen);
}
renderXXerlay() {
// Workaround for Android position absolute bug
// issue : https://github.com/facebook/react-native/issues/8923
let visible = this.state.isMenuVisible;
return (
<TouchableWithoutFeedback
onPress={() => { this.hideMenu() }}>
<View style={[styles.XXerlayView, { height: visible ? null : 0 }]} />
</TouchableWithoutFeedback>
)
}
renderSyncXXerlay() {
let visible = this.props.pageStatus.syncModal;
if (!visible) {
return null;
}
return (
<XXSyncXXerlay
visible={visible} />
)
}
//
// EVENTS
//
onPressMenu(pageId) {
requestAnimationFrame(() => {
if (this.currentPageId !== pageId) {
if (pageId === 'DemoTestPage') {
NavUtils.push(this.navigator, pageId);
}
else {
NavUtils.resetTo(this.navigator, pageId);
}
this.updateStatusBarStyle(pageId);
}
this.hideMenu();
});
}
onPressLogout() {
this.setState({ loggingOut: true }, () => {
this.props.logout();
});
}
onUpdateMenu(isMenuVisible) {
if (isMenuVisible === undefined || this.previousMenuVisible === isMenuVisible) {
return;
}
this.previousMenuVisible = isMenuVisible;
// When menu needs to be opened
if (isMenuVisible) {
StatusBarManager.setStyle('light-content', isMenuVisible);
Animated.timing(
this.state.animatedPosition,
{
tXXalue: {
// Animate the RootPage to the right.
// x: 317 / 375 * DEVICEINFO.SCREEN_WIDTH,
// y: 126 / 667 * DEVICEINFO.SCREEN_HEIGHT,
x: 317 / 375 * DEVICEINFO.SCREEN_WIDTH,
y: 1 / 1000 * DEVICEINFO.SCREEN_HEIGHT
},
// duration: 300
// debugging mode
duration: 300
}
).start();
return;
}
// When menu needs to be closed
StatusBarManager.setStyle(this.routeStatusBarStyle, isMenuVisible);
Animated.timing(
this.state.animatedPosition,
{
tXXalue: {
x: 0,
y: 0
},
duration: 300
}
).start();
}
//
// Methods
//
initializeBluetooth() {
// Event listeners for XXBluetoothManager
this.itemDeviceStatusChanged = XXBluetoothEventEmitter.addListener('itemDeviceStatusChanged', event => {
// console.log('ROotpage; . initializeBluetooth: ', event)
this.getConnectedDevice();
});
this.getConnectedDevice();
}
destroyBluetooth() {
if (this.itemDeviceStatusChanged) {
this.itemDeviceStatusChanged.remXXe();
}
}
getConnectedDevice() {
console.log('when does getconnectedDevice get fired inside rootpage? :D', this.props)
XXBluetoothManager.getDeviceAddress((error, address) => {
if (error) {
// Not connected
this.setState({ deviceAddress: null });
return;
}
// console.log('when can we read error, address', error, address)
this.setState({ deviceAddress: address });
});
}
initAndroidHardwareBackEvent() {
BackHandler.addEventListener('hardwareBackPress', () => {
if (!this.navigator) {
return false;
}
if (this.navigator.state.index > 0) {
const backAction = NavigationActions.back({
key: null
});
this.navigator.dispatch(backAction);
return true;
}
return false;
});
}
toggleMenu() {
this.props.toggleRootMenu();
}
hideMenu() {
this.props.closeRootMenu();
}
}
const mapStateToProps = (state) => {
return {
signinStatus: state.page.signin,
pageStatus: state.page.root,
profile: state.user.profile,
devices: state.device.devices,
aDeviceHasBeenConnected: state.device.aDeviceHasBeenConnected,
}
}
const mapDispatchToProps = (dispatch) => {
return {
logout: () => {
dispatch(logout());
},
closeSyncModal: () => {
dispatch(closeSyncModal());
},
toggleRootMenu: () => {
dispatch(toggleRootMenu());
},
openRootMenu: () => {
dispatch(openRootMenu());
},
closeRootMenu: () => {
dispatch(closeRootMenu());
},
}
}
export default connect(mapStateToProps, mapDispatchToProps)(RootPage);
const styles = StyleSheet.create({
rootView: {
flex: 1,
flexDirection: 'column',
},
menuView: {
width: DEVICEINFO.SCREEN_WIDTH,
height: '100%',
backgroundColor: '#aab942',
position: 'absolute',
top: 0,
left: 0
},
menuTopArea: {
backgroundColor: '#b7c846',
// height: DEVICEINFO.SCREEN_HEIGHT * 0.35,
height: DEVICEINFO.SCREEN_HEIGHT * 0.28,
width: '100%',
flexDirection: 'column',
},
menuBottomArea: {
// backgroundColor: '#aab942',
width: '100%',
flex: 1,
flexDirection: 'column',
},
animatedView: {
position: 'relative',
flex: 1,
flexDirection: 'column',
backgroundColor: '#fff'
},
profileImageSubContainer: {
height: '100%',
flexDirection: 'column',
justifyContent: 'center',
marginLeft: 40,
marginTop: 10,
},
profileImage: {
width: DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 70 : 80,
height: DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 70 : 80,
borderRadius: (DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 70 : 80) / 2
},
profileText: {
marginTop: DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 6 : 16,
fontSize: Math.min(LAYOUTINFO.DESIGN_WIDTH_RATIO * 20, 21),
color: '#fff',
backgroundColor: 'transparent'
},
deviceText: {
marginTop: DEVICEINFO.IS_EXTRA_SMALL_SCREEN ? 6 : 16,
fontSize: Math.min(LAYOUTINFO.DESIGN_WIDTH_RATIO * 14, 15),
color: '#fff',
backgroundColor: 'transparent'
},
menuContainer: {
flex: 1,
width: '100%',
height: '100%',
flexDirection: 'column',
alignItems: 'flex-start',
},
// menubutton
menuButtonTouch: {
marginTop: 25 * HEIGHT_RATIO,
marginLeft: 38,
},
menuButtonView: {
flexDirection: 'row',
alignItems: 'center'
},
menuIcon: {
width: 18,
height: 18,
resizeMode: 'contain'
},
// menubuttontext
menuText: {
marginLeft: 17,
fontSize: Math.min(LAYOUTINFO.DESIGN_WIDTH_RATIO * 22, 22),
color: '#fff'
},
XXerlayView: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
width: null,
height: null,
backgroundColor: 'rgba( 255, 255, 255, 0.0001 )',
zIndex: 9999
}
});
Here is the RootNavigator page
import { Platform } from 'react-native';
import { StackNavigator } from 'react-navigation';
// Pages
import EntryPage from '../EntryPage/EntryPage';
import SigninPage from '../SigninPage/SigninPage';
import SignupPage from '../SignupPage/SignupPage';
import ReportSinglePage from '../ReportSinglePage/ReportSinglePage';
import HomePage from '../HomePage/HomePage';
import VolumePage from '../VolumePage/VolumePage';
import ReportPage from '../ReportPage/ReportPage';
import ReportDetailPage from '../ReportDetailPage/ReportDetailPage';
import ItemListPage from '../ItemListPage/ItemListPage';
import AddItemPage from '../AddItemPage/AddItemPage';
import SupportPage from '../SupportPage/SupportPage';
import SettingsPage from '../SettingsPage/SettingsPage';
import SoundPage from '../SoundPage/SoundPage';
import VerticalSoundPage from '../SoundPage/VerticalSoundPage';
import SoundSyncPage from '../SoundSyncPage/SoundSyncPage';
import TestPage from '../TestPage/TestPage';
import iOSTestPage from '../TestPage/iOSTestPage';
import FittingTestPage from '../TestPage/FittingTestPage';
import SendResultSlide from '../SoundSyncPage/SendResultSlide';
import ModePage from '../ModePage/ModePage';
import PolicyPage from '../PolicyPage/PolicyPage';
import PrivacyPage from '../PrivacyPage/PrivacyPage';
import TermsAndConditionsPage from '../TermsAndConditionsPage/TermsAndConditionsPage';
import SelectTutorialPage from '../TutorialPage/SelectTutorialPage';
import PreparingTutorial from '../TutorialPage/PreparingTutorial';
import AddItemTutorial from '../TutorialPage/AddItemTutorial';
import HearingTestTutorial from '../TutorialPage/HearingTestTutorial';
import ReportTutorial from '../TutorialPage/ReportTutorial';
import EqualizerTutorial from '../TutorialPage/EqualizerTutorial';
import AddItemTutorialCompletion from '../TutorialPage/AddItemTutorialCompletion';
import AddItemTutorialFailure from '../TutorialPage/AddItemTutorialFailure';
import HearingTestTutorialCompletion from '../TutorialPage/HearingTestTutorialCompletion';
// import RootPage from '../RootPage/RootPage';
const RootNavigator = StackNavigator(
{
// RootPage: {screen: RootPage},
EntryPage: { screen: EntryPage },
SignupPage: { screen: SignupPage },
HomePage: { screen: HomePage },
TestPage: { screen: TestPage },
iOSTestPage: { screen: iOSTestPage },
FittingTestPage: { screen: FittingTestPage },
ReportPage: { screen: ReportPage },
ReportDetailPage: { screen: ReportDetailPage },
ReportSinglePage: { screen: ReportSinglePage },
ItemListPage: { screen: ItemListPage },
AddItemPage: { screen: AddItemPage },
SoundPage: { screen: VerticalSoundPage },
SoundSyncPage: { screen: SoundSyncPage },
SupportPage: { screen: SupportPage },
SettingsPage: { screen: SettingsPage },
VolumePage: { screen: VolumePage },
SendResultSlide: { screen: SendResultSlide },
PolicyPage: { screen: PolicyPage },
PrivacyPage: { screen: PrivacyPage },
TermsAndConditionsPage: { screen: TermsAndConditionsPage },
SelectTutorialPage: { screen: SelectTutorialPage },
PreparingTutorial: { screen: PreparingTutorial },
AddItemTutorial: { screen: AddItemTutorial },
HearingTestTutorial: { screen: HearingTestTutorial },
ReportTutorial: { screen: ReportTutorial },
EqualizerTutorial: { screen: EqualizerTutorial },
AddItemTutorialCompletion: { screen: AddItemTutorialCompletion },
AddItemTutorialFailure: { screen: AddItemTutorialFailure },
HearingTestTutorialCompletion: { screen: HearingTestTutorialCompletion },
},
{
initialRouteName: 'EntryPage',
navigationOptions: {
header: null,
}
},
{
headerMode: 'none'
}
);
export default RootNavigator;
And just in case, here is the helper function this I'm trying to use:
static push(navigator, pageId, params = {}) {
let newParams = { navIndex: 1 };
if (navigator.state.index) {
newParams.navIndex = navigator.state.index + 1;
}
else if (navigator.state.params && navigator.state.params.navIndex) {
newParams.navIndex = navigator.state.params.navIndex + 1;
}
Object.assign(newParams, params);
navigator.dispatch({ type: 'Navigation/NAVIGATE', routeName: pageId, params: newParams });
}