I have a React component getting an item's info and returning JSX:
const detail = props => {
const service = new Services()
const detail = service.findItem(props.match.params.id)
.then(item => {
console.log(item) // logs correct details, including the title property
return item
})
.catch(err => console.log(err))
return (
<h1>{detail.title}</h1> // !! prints nothing inside the <h1> tag
)
}
As seen above, returning object logs correctly all properties, but when trying to access them through JSX, no info is shown.
There are no console errors.
Its because the detail has not yet resolved, you can have React.Component and use
export class detail extends React.Component {
state = {
item: {}
}
componentDidMount(){
const service = new Services()
const detail = service.findItem(props.match.params.id)
.then(item => {
this.setState({ item:item });
})
.catch(err => console.log(err))
}
render() {
return <h1>{this.state.item.title}</h1>
}
}
Related
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 }))
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 have a container component in which I get the ID and drop this ID into the function and the request goes, in principle, the props should come right away, but they are undefined. But when you re-enter the same component, the necessary props are shown.
Explain how to make props appear on the first render?
class View extends React.Component {
componentDidMount() {
let id = this.props.match.params.id;
this.props.GetProjData(id);
}
render() {
return <ProjView {...this.props}></ProjView>;
}
}
let mapStateToProps = state => {
return {
initialValues: {
NameProj: state.project.OneProject.NameProj,
Text: state.project.OneProject.Text,
target: state.project.OneProject.target,
startdate: state.project.OneProject.startdate,
enddate: state.project.OneProject.enddate
},
error: state.settings.error,
loading: state.settings.loading
};
};
My request
export const GetProjData = data => async (
dispatch,
getState,
{ getFirestore }
) => {
const firestore=getFirestore()
try {
await firestore
.collection("Projects")
.where("idProject", "==", data)
.get().then(snap => {
snap.forEach(doc => {
let project=doc.data()
console.log(doc.data());
dispatch({type:getOne,project})
});
})
} catch (err) {}
};
If I'm understanding the flow of your app correctly, you need to account for the renders between when you request your project data and when you receive the project data.
class View extends React.Component {
// constructor fires first so we might as well move it here
constructor(props) {
const id = props.match.params.id;
props.GetProjData(id);
}
render() {
// Your component will rerender before receiving the new data.
// We block the component from mounting so that initialValues
// gets set only when we have the data needed
if (this.props.initialValues && this.props.initialValues.NameProj) {
// A better way to do this would be to listen to a loading variable
// that gets updated when your request finishes
return <ProjView {...this.props} />;
}
return null; // or loading graphic
}
}
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>
);
}
I have a problem fetching data from firebase with componentDidMount().
Fetching the data working fine but the problem is when it comes to lifecycle method. I console.log out the fetched data.
it fetched data when the component renders and after it fetched, the data become undefined and my render method appeared and disappeared in 0.001sec.
Do I need to store the props data into the state in order to not to disappear
Thank you for the help!
Action
export const fetchUserAddressbook = () => {
const { currentUser } = auth;
return dispatch => {
database
.ref(`users/${currentUser.uid}/shippingAddress`)
.on('value', snapshot => {
dispatch({
type: FETCH_SHIPPING_ADDRESS_SUCCESS,
payload: snapshot.val()
});
});
};
};
class
componentDidMount() {
this.props.fetchUserAddressbook();
}
render(){
return
(
<div>{this.renderAddressCard(this.props.shippingAddressBook)}</div>
)
const mapStateToProps = state => {
return {
shippingAddressBook: state.user.shippingAddressBook
};
}
renderMethod
renderAddressCard(shippingAddressBook) {
return _.map(shippingAddressBook, (value, uid) => {
return (
<Card header={value.companyName} />
);
});
}