class MyAttendees extends React.Component {
static contextType = AuthContext;
constructor(props){
super(props);
this.state = {
barcodesData: []
}
}
componentDidMount() {
this.fetchBarcodeData()
}
fetchBarcodeData() {
const { currentUser, GetBarcodesByUser } = this.context; // getting current user logged in and a function
const uid = currentUser.uid; // uid of the user
GetBarcodesByUser(uid) // this will return a array of string containing barcodes id
.then( data => this.setState({ barcodesData: data }))
}
// force rerender
forceUpdater() {
this.forceUpdate();
}
render() {
return (
<div>
{
// trying to render the array list
// this is not rerendering even after the barcodes is updated
this.state.barcodesData.map((item) => {
console.log("item: ", item)
return <h1 key={item}>{item}</h1>
})
}
</div>
)
}
}
export default MyAttendees;
const GetBarcodesByUser = async ( uid: string ): string[] => {
const data = await getBarcodesByUser(uid);
return data;
}
export const getBarcodesByUser = async ( uid: string ): string[] => {
const result = [];
const q = query(collection(firestore, "qrcode"), where("uid", "==", uid));
onSnapshot(q, (querySnapshot): string[] => {
querySnapshot.forEach( document => {
result.push( document.id )
})
})
return result;
}
Things that I have tried
at first I was using function approach with useEffect.
I tried to use function to render array.
I tried to use the fetching function inside componentDidMount() function
Tried forceUpdate
Any of the above method is not working
Not 100% that was the entire console.log so my guess is you are mapping the wrong bit. Try changing your state to set like this
.then( response => this.setState({ barcodesData: response.data }))
Related
I want to fetch data that returns successfully after componentDidMount, but before there is an error that singer.data is undefined:
// imports
export default class LookSinger extends Component {
state = {
singer: {}
}
componentDidMount () {
let { singer } = this.props.location.state;
singer = singer.replace(/ /g,"+");
const fetchData = async () => {
try {
const response = await fetch(
`http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist=${singer}&api_key=a3c9fd095f275f4139c33345e78741ed&format=json`
);
const data = await response.json();
this.setState({
singer: data
})
} catch (error) {
console.log(error.message);
}
}
fetchData();
}
render() {
let singer = this.state.singer
return(
<div>
{console.log(singer.artist.name)} // gives undefined but after fetching artist.name absolutely exists
</div>
)
}
}
Url is:http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist=Ariana+Grande&api_key=a3c9fd095f275f4139c33345e78741ed&format=json
The problem is here:
{console.log(singer.artist.name)}
In the initial render, singer.artist is undefined and if you call singer.artist.name it will throw error. name of undefined.... You just need to wait for data to fetch and update the state.
Try like this
export default class LookSinger extends Component {
state = {
singer: {}
}
componentDidMount () {
let { singer } = this.props.location.state;
singer = singer.replace(/ /g,"+");
const fetchData = async () => {
try {
const response = await fetch(`http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&artist=${singer}&api_key=a3c9fd095f275f4139c33345e78741ed&format=json`);
const data = await response.json();
this.setState({ singer: data })
} catch (error) {
console.log(error.message);
}
}
fetchData();
}
render() {
const { singer } = this.state
if (!singer.artist) { // <-- Check if the data is present or not.
return <div>Loding singer info...</div>
}
return(
<div>
<h1>{singer.artist.name}</h1>
</div>
)
}
}
You do let singer = this.state but there's no this.setState({ singer: ... }) in your code. Instead of this.setState({ data }), try this.setState({ singer: data })
Set you state as below and,
const data = await response.json();
this.setState({
singer: data
})
and you can log it out likes this,
console.log(this.state.singer)
I have a very simple react native screen which looks as follows:
class BasicScreen extends React.Component {
state = {
data: [],
myItems: [],
};
componentDidMount() {
this.checkforItems();
}
checkforItems = async () => {
AsyncStorage.getItem('MyItems').then(item => {
if (item) {
this.setState({
myItems: JSON.parse(item),
});
} else {
console.log('No data.');
}
});
};
render() {
return (
<View>/* A detailed view */</View>
)
}
}
The problem is that it causes the following error:
Cannot update a component from inside the function body of a different component.
I'm not sure how to fix this. Please help.
This looks like it is just going to overwrite myItems with whatever the most recent mapped item is rather than appending each new item.
You might try mapping the items to an array in componentDidMount() and then set the state in a useEffect call.
const BasicScreen = () => {
const [myData, setData] = useState([]);
const [myItems, setItems] = useState([]);
const checkForItems = () => {
var storageItems = AsyncStorage.getItem("MyItems").then((item) => {
if (item) {
return JSON.parse(item);
}
});
setItems(storageItems);
};
useEffect(() => {
async function getItems() {
await checkForItems();
}
getItems();
}, []);
return (
<View>
<Text>{myItems[0]}</Text>
</View>
);
};
export default BasicScreen;
I've got a massive list of about 50 dog photos that I'm pulling in from an API into a react component, and I only want to display the first 10.
I wrote the following function to attempt to filter out only the first 10 photos url's in the array
setData = async () => {
const x = await fetch('https://dog.ceo/api/breed/hound/images')
const y = await x.json()
const z = await y.message
let newArr =[]
for (let i=0; i<z.length; i++){
if (i<=10){
newArr.push(z[i])
}
}
return newArr
}
then used the result of that to set the state
componentDidMount(){
const dogList = this.setData()
this.setState({
dog: dogList
})
}
....which then was supposed to render just the first 10 dog photos:
render() {
return (
<div>
<h1>Rate My Dogue</h1>
{
this.state.dog.map(doggie => {
return <img className = 'img' src = {doggie}></img>
})
}
</div>
);
}
}
and unsurprisingly, it didn't work. Does anyone have suggestions on how I can prune my API call?
Here's the full component:
import React from 'react';
import './styles.css'
class App extends React.Component {
constructor(){
super()
this.state = {
dog: []
}
}
setData = async () => {
const x = await fetch('https://dog.ceo/api/breed/hound/images')
const y = await x.json()
const z = await y.message
let newArr =[]
for (let i=0; i<z.length; i++){
if (i<=10){
newArr.push(z[i])
}
}
return newArr
}
componentDidMount(){
const dogList = this.setData()
this.setState({
dog: dogList
})
}
render() {
return (
this.state.loading ? <h1> Dogues Loading.....</h1>
:
<div>
<h1>Rate My Dogue</h1>
{
this.state.dog.map(doggie => {
return <img className = 'img' src = {doggie}></img>
})
}
</div>
);
}
}
export default App;
You have an async function (setData) which returns a promise and to get the value of that async function you need to do a .then() method. So something like this in your componentDidMount
componentDidMount() {
this.setData()
.then((res) => {
this.setState({
dog: res,
});
})
.catch((error) => console.log(error));
}
Or, make your componentDidMount an async function and await the results of setData.
async componentDidMount() {
try {
const dogList = await this.setData();
this.setState({
dog: dogList,
});
} catch (error) {
console.log(error);
}
}
In your question, you stated you wanted the first 10 photos so your setData should have a check like this since your loop is starting at the index of 0.
setData = async () => {
const x = await fetch("https://dog.ceo/api/breed/hound/images");
const y = await x.json();
const z = await y.message;
let newArr = [];
for (let i = 0; i < z.length; i++) {
if (i <= 9) {
newArr.push(z[i]);
}
}
return newArr;
};
Please don't forget to add a key prop to your map method in the render function.
After I recieved the data from firebase and store it into the post state and I try to pass each data to another component one one data is been sent to the prop anyone have.
Any idea as to why?
import React, { Component } from 'react';
import BlogPost from './BlogPost'
import firebase from '../../config/fbConfig'
class BlogList extends Component {
state = {
posts: []
}
componentDidMount() {
const db = firebase.firestore()
db.collection('posts').get().then(snapshot => {
snapshot.docs.forEach(post => {
let id = post.id
let postData = post.data()
postData['id'] = id
this.setState({
posts: [...this.state.posts, postData]
})
})
})
}
render() {
console.log(this.state.posts)
return (
<>
{this.state.posts ?
this.state.posts.map(post =>
<BlogPost post={post} key={post.id} />
)
: <h1>loading</h1>}
</>
);
}
}
export default BlogList;
The issue is in how you update the state, you must either use functional setState since you call setState within a loop and use this.state.data to update state, but state updates are not performed immediately but happen asynchronously
componentDidMount() {
const db = firebase.firestore()
db.collection('posts').get().then(snapshot => {
snapshot.docs.forEach(post => {
let id = post.id
let postData = post.data()
postData['id'] = id
this.setState(prev => ({
posts: [...prev.posts, postData]
}))
})
})
}
or even better update once all the data is available
componentDidMount() {
const db = firebase.firestore()
db.collection('posts').get().then(async snapshot => {
const data = snapshot.docs.map(post => {
let id = post.id
let postData = post.data()
postData['id'] = id
return postData;
});
this.setState(prev => ({
posts: [...prev.posts, ...data]
}));
})
}
I am trying to display a list of user repositories. Through the spread operator attempts to spell the object. However, I do not know if this is a good method, there are no errors in the console, but nothing appears on the screen. This is my code.
class ItemUserDetail extends React.Component {
constructor() {
super();
this.state = {
usersRepos: []
};
}
componentDidMount() {
const { user } = this.props.match.params;
const url = `https://api.github.com/users/${user}/repos`;
fetch(url)
.then(res => res.json())
.then(json => this.setState({ usersRepos: json }));
}
render() {
const Repos = this.state.usersRepos ? { ...this.state.usersRepos } : null;
return (
<div>
<p>{Repos.name}</p>
</div>
);
}
}
export default ItemUserDetail;
Since you are returning an array of repositories, your render method should look like this
render() {
const Repos = this.state.usersRepos ? this.state.usersRepos : null; // you don't need this
const { userRepos } = this.state; // destructure
return (
<div>
{userRepos.map(repo => <p key={repo.id}>{repo.name}</p>)}
</div>
);
}