How to push data into state array in react native - arrays

Suppose I have an array of ids that reflects my images [aaa, bbb, ccc]and I will be using that data to get my images.
I want to use these ids and get my images and store them in an array state which would be used to display my images in flatlist.
My code is as follows.
getIDs() {
fetch(config)
.then((response) => {
return response.json();
})
.then(async (data) => {
data.map(async id => {
await this.setImages(id.id)
} );}) }
async setImages(imageID) {
await fetch(config ) //where image Id is used
.then((response) => {
return response.json();
} })
.then(async (data) => {
await this.setState({ images: this.state.images.concat(data.content), isLoading: false }
})
The problem with this setState is that it changes the sequence of my images. I want to load my images in a specific sequence that I am getting from my database.
My Flatlist is as follows
<FlatList
data={[...this.state.images]}
numColumns={3}
renderItem={({ item, index }) => {
return (
<Image source={{ uri: 'data:image/png;base64,' + item }} />
);
}}
keyExtractor={(item, index) => index.toString()}
/>

Instead of setState there for each image, first make an array to contain images and push image there so that theres no change in order and while retrieving do that like you used to do
let imagesArray=[];
getIDs() {
fetch(config)
.then((response) => {
return response.json();
})
.then(async (data) => {
data.map(async id => {
await this.setImages(id.id)
} );
}
this.setState({imagesArray:imagesArray})
) }
async setImages(imageID) {
await fetch(config ) //where image Id is used
.then((response) => {
return response.json();
} })
.then(async (data) => {
// await this.setState({ images: this.state.images.concat(data.content), isLoading: false }
imagesArray.push (data.content)
}) :,
hope it helps

Related

Firebase promise - unable to set state, state array is empty

I have a promise to get a firebase collection and then return respective data (all according firebase documentation).
The data is returning fine, the only problem is that it seems that I am unable to set the collection data to a state array. When console.log(chats)this returns an empty array.
The data is returning fine as adding a console.log(doc.data()) in the first then logs the data ok but then it is empty.
What am I doing wrong in the promise?
const HomeScreen: React.FC<Props> = ({ navigation}) => {
const [chats, setChats] = useState<{[key: string]: any}>([]);
useEffect(() => {
const chatsArray = [{}];
db.collection("chats")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
chatsArray.push({
id: doc.id,
data:doc.data(),
})
});
})
.then(() => {
setChats(chatsArray)
console.log(chats);
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
}, []);
return (
<SafeAreaView>
<ScrollView style={styles.container}>
{chats go here}
</ScrollView>
</SafeAreaView>
)
}
export default HomeScreen;
The console.log(chats); doesn't work, since updating the state is a asynchronous operation that won't have completed by the time you log the value. Try console.log(chatsArray); to see the actual value.
In addition, consider passing the array as the result along the promise chain instead of using a variable in the context:
db.collection("chats")
.get()
.then((querySnapshot) => {
return querySnapshot.docs.map((doc) => {
return {
id: doc.id,
data:doc.data(),
}
});
})
.then((chatsArray) => {
setChats(chatsArray)
console.log(chatsArray);
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
Or simpler and with the same result:
db.collection("chats")
.get()
.then((querySnapshot) => {
const chatsArray = querySnapshot.docs.map((doc) => {
chatsArray.push({
id: doc.id,
data:doc.data(),
})
});
setChats(chatsArray)
console.log(chatsArray);
})
.catch((error) => {
console.log("Error getting documents: ", error);
});

Flatlist not rendering data properly even after getting data appended in React Native?

I am adding data in flatlist in onMomentumScrollEnd, I recieved the data from my REST API still not getting data rendered properly.
<FlatList
onMomentumScrollEnd={() =>
this.state.pageno <= this.state.maxPage
? this.getData('', 1, this.state.pageno + 1)
: null
}
onEndReachedThreshold={0.5}
data={this.state.responseData}
ItemSeparatorComponent={this.ItemSeparatorLine}
keyExtractor={(item, index) => index.toString()}
showsVerticalScrollIndicator={true}
renderItem={({item}) => (this.renderMyItem(item)}
/>
Here is the function for appending data which is getting data perfectly in this.state.responseData
getData(text, apiType, pageno) {
this.showLoader();
this.setState({
pageno: pageno,
search: text,
type: apiType,
});
let data = {
pageNo: pageno,
type: apiType,
search: text,
sortedBy: '',
sortedIn: 'DESC',
filter: {},
};
const headers = {
'X-Auth-Token': this.state.token,
'Content-Type': 'application/json',
};
console.log(data);
axios
.post(PIDataApi, data, {headers: headers})
.then(response => {
this.setState({
isLoading: false,
});
if (response.data.status != 2000) {
Toast.show(response.data.error.errorMessage, Toast.SHORT);
} else {
if (response.data.data.resource != null) {
let historyData = response.data.data.resource;
console.log('api response:', historyData);
if (this.state.pageno > 1) {
this.setState({
responseData: [...this.state.responseData, historyData],
maxPage: response.data.data.maxPage,
});
console.log('responseData : ', this.state.responseData);
} else {
this.setState({
responseData: historyData,
maxPage: response.data.data.maxPage,
});
}
} else {
Toast.show(response.data.data.message, Toast.SHORT);
}
}
})
.catch(error => {
console.error(error);
});
}
you can see how the data rendered in the list, even after getting data appended correctly
The response that you get from the axios request sends you historyData in the form of an array, however you are setting it in state directly without spreading
Also when you update state based on previous state, do make use of functional setState
if (this.state.pageno > 1) {
this.setState(prevState => ({
responseData: [...prevState.responseData, ...historyData], // spread historyData here
maxPage: response.data.data.maxPage,
}));
} else {
this.setState({
responseData: historyData,
maxPage: response.data.data.maxPage,
});
}

update state with data return undefined

I have one state called data that is empty object state={data:{}} I called RestAPI updated state USING set state when I console log it returned the data in the correct format but data that I need is this.state.data.title.rendered it says undefined but in console log it has data
Rest Api is like this:
{id:5,title:{rendered:"home is good"}}
fetch(`http://localhost/react-wordpress/wp-json/wp/v2/posts/${this.props.match.params.id}`)
.then((response) => response.json())
.then((responseJson) => {
const { title, fimg_url, content } = responseJson;
this.setState({ title, fimg_url, content });
this.setState({ data: responseJson })
})
.catch((error) => {
console.error(error);
});
In rendered method {this.state.data.title.rendered} return undefined while {this.state.title.rendered} return correct
Yes. Maybe it is undefined before fetching from backend.
So you need to validate if it is okay to render it like below:
const { data } = this.state;
return (
<div>
{ data && data.title && data.title.rendered
&& ( <h1>data.title.rendered</h1> )
}
<div>
);
try like this
fetch(`http://localhost/react-wordpress/wp-json/wp/v2/posts/${this.props.match.params.id}`)
.then((response) => response.json())
.then((responseJson) => {
const { title, fimg_url, content } = responseJson;
this.setState({ data: {title, fimg_url, content} });
})
.catch((error) => {
console.error(error);
});

How can I call another api in flat list?

I have one API which has title, body, and user-id, and I want to print User Name with the help of another API. So how can I do it?
I have listed both APIs in below.
https://jsonplaceholder.typicode.com/posts
https://jsonplaceholder.typicode.com/users/1 // ${id}
getUser(id) {
let userData = fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
.then(response => response.json())
.then((responseJson) => {
return responseJson.name
})
.catch(error => console.log(error)) //to catch the errors if any
console.log(userData);
return userData;
};
what you can do is first get the posts and save it inside a variable .
then inside a map call other api to get the user data and append the user data in the variable
example
fetch('https://jsonplaceholder.typicode.com/posts',)
.then(response => {
let new_post = [];
let posts = response.json() ;
Promise.all(
posts.map(item => {
fetch('https://jsonplaceholder.typicode.com/users/'+item.userId)
.then(res =>{
item['user'] = res.json() ;
console.log(item)
new_post.push(item)
})
})
)
.then(() => {
this.setState({testing:new_post})
})
})
then in your flatlist display username by
<FlatList
data={this.state.testing}
renderItem={({item}) =>(
<View>
<Text>other</Text>
<Text>{item.user.email}</Text>
</View>
)
}
/>
OR if your are using axios to get data change code to
axios.get('https://jsonplaceholder.typicode.com/posts',)
.then(response => {})

react native get response from then and assign to variable

I am trying to get thumbnail path and storing to a variable to be used, But I am getting undefined
getThumbnail(filePath){
let thumbnailURL = RNThumbnail.get(filePath)
.then((response) => response.path)
.then((responseData) => {
console.warn(responseData);
return responseData;
}).catch(error => console.warn(error));
alert(thumbnailURL);
//return thumbnailURL;
}
.then doesn't work like that, it won't return a value. You could do:
let thumbnailURL;
RNThumbnail.get(filePath)
.then((response) => response.path)
.then((responseData) => {
thumbnailURL = responseData;
alert(thumbnailURL);
}).catch(error => console.warn(error));
but you have to continue computation inside the second then call because the value is only going to be reliable there
You're better off using async/await, just refactor your code to this:
async function getThumbnail(filePath){
try {
let thumbnailURL = await RNThumbnail.get(filePath)
alert(thumbnailURL)
} catch(err) {
console.warn(err)
}
read more about async / await
For React app, most likely you will want to set the response as state:
state = {
thumbnailURL: ''
}
getThumbnail = (filePath) => {
RNThumbnail.get(filePath)
.then(response => response.path)
.then(responseData => {
this.setState({
thumbnailURL: responseData
})
})
.catch(error => console.warn(error))
}
render() {
return (
<img src={this.state.thumbnailURL} />
)
}
You will need arrow function on getThumbnail for lexical binding so that you can access this.setState().
Edit:
You can't actually make getThumbnail() return thumbnailURL value right away. getThumbnail() can however return the promise, and you resolve it at the place where you want access to thumbnailURL:
getThumbnail = filePath => {
return RNThumbnail.get(filePath)
.then(response => response.path)
.then(responseData => responseData)
.catch(error => console.warn(error))
}
IWannaAccessThumbnailURLHere = () => {
this.getThumbnail('....')
.then(thumbnailURL => {
// do things with thumbnailURL
})
}
Or, use setState, re-render then you can access this.state.thumbnailURL in the next render-cycle.

Resources