persist firebase data in react-native app - javascript

I am trying to build my first app on react-native, but I have problem with that. I want to show my data from firebase and also the data which insert to firebase does not get deleted when I reload the app. That's what I have in my render:
let tags = this.state.tagArray.map((val, key) => {
return <TagContainer key={key} keyval={key} val={val}
deleteMethod={() => this.deleteTag(key)} />
});
this is my firebase config:
this.itemRef=this.getRef().child('tags');
getRef(){
return firebaseApp.database().ref();
}
getItems(itemRef){
itemRef.on('value',(snap)=>{
let items=[];
snap.forEach((child) => {
items.push({
title:child.val().title,
_key:child.key
});
});
Array.prototype.push.apply(this.state.tagArray, items);
this.setState({ tagArray: this.state.tagArray })
});
this my addtag function where I set my tagArray:
addTag() {
if (this.state.tagText) {
this.state.tagArray.push({
'tag': this.state.tagText
});
this.setState({ tagArray: this.state.tagArray })
this.setState({ tagText: '' })
this.itemRef.push({title:this.state.tagText});
}
}

You are not supposed to push data into state object. No state changes are allowed without using setState().
addTag() {
if (this.state.tagText) {
let tagArray = [...this.state.tagArray,{'tag': this.state.tagText}]
this.setState({ tagArray: tagArray,tagText: '' }, ()=>{
this.itemRef.push({title:this.state.tagText});
})
}
}

Related

When I upload a image firebase storage getdownloadUrl() put download url In Firestore Collections but not set it in React JS

I am trying to upload an Image to Firebase Storage and after successful upload I am trying to insert image downloadURL to Firestore collection at the same time.
How to do it? Here is the code in which Uploading Image is working fine but firestore is not working.
dbRef = firebase.firestore().collection('stack_overflow').doc()
constructor(props) {
super(props);
this.state = {
question_id: this.dbRef.id,
question_title: '',
question_image: null,
question_image_url: '',
};
}
dataOnChange = (e) => {
const state = this.state
state[e.target.name] = e.target.value
this.setState(state)
}
handleImageOnChange = e => {
if (e.target.files[0]) {
const question_image = e.target.files[0]
this.setState(() => ({question_image}))
}
}
onSubmitData = (e) => {
e.preventDefault()
const {
question_id, question_title, question_image, question_image_url
} = this.state;
/*image upload and download*/
const uploadImage = storage.ref(`/stack_gallery/${cat_image.name}`).put(cat_image);
uploadImage.on('state_changed', (snapshot) => {
console.log("Image Upload Progress")
},
(error) => {
console.log(error);
},
/*() => {
storage.ref('quote_gallery').child(question_image.name).getDownloadURL().then(question_image_url => {
console.log(question_image_url);
this.setState({question_image_url});
})
}*/);
storage.ref('stack_gallery').child(question_image.name).getDownloadURL().then(question_image_url => {
console.log(question_image_url);
this.setState({question_image_url});
})
this.dbRef.set({
question_id, question_title, question_image_url
}).then((docRef) => {
this.add({
question_id: '',
question_title: '',
question_image_url: this.state.cat_image_url
})
}).catch((error) => {
console.error("Error Adding Document: ", error)
})
}
Please check my code where is problem and how to solve this problem .
As I see your code you saved question_image_url to this.state, and I think we dont have to save it to state as we use state to render JSX.
Once you got url in callback then why don't you run saving to firestore in callback?
And you used firestore().collection().doc().set, this works wrong. you should indicate the doc_id to set because set is updating function of current doc_id.
If you want to add new doc then you can use add function from collection that wrapps whole docs.
uploadImage.on('state_changed', (snapshot) => {
console.log("Image Upload Progress")
},
(error) => {
console.log(error);
},
function() {
uploadImage.snapshot.ref.getDownloadURL().then(function(downloadURL) {
firebase.firestore().collection('stack_overflow').add({
question_title: question_title,
question_image: question_image,
question_image_url: downloadURL
})
.then((res) => {
let id = res.id; //receive id of doc added
firebase.firestore().collection('stack_overflow').doc(id).set({question_id:id},{merge:true})
})
});

when i used creatorId:getters.user.id it tell me id undefined

Here is all the data that I want to send to the firebase, all work but the first one doesn't work, the one called creatorId:
ReceveMeetup ({commit ,getters } ,payload) {
const meetup = {
title:payload.title,
location:payload.location,
date:payload.date,
time:payload.time,
url:payload.url,
content:payload.content,
Here I am trying to make the post take the same id of the writer that saved in the database and couldn't create that in firebase to bring it back after
creatorId:getters.user.id ,
}
// send the data to firebase
firebase.database().ref('meetups').push(meetup).then(
(data) => {
const key = data.key
commit('ReceveMeetup',{
...meetup,
id:key,
}) })
.catch((error) => {console.log(error) ; } )
},
getters: {
loadedMeetups (state) {
return state.loadedMeetups.sort((meetupA ,meetupB)=> {
return meetupA.date ===meetupB.date
})
},
featureMeetups (state , getters){
return getters.loadedMeetups.slice(0,5)
},
loadedMeetup (state) {
return (meetupId) => {
return state.loadedMeetups.find((meetup)=> {
return meetup.id === meetupId
})}
},
user (state) {return state.user },
loading (state) {return state.loading},
error (state) {return state.error},
}
});

How to set state of cart when no items?

In my E-Commerce project, the products are stored in localStorage. componentDidMount() gets all these products from localStorage and displays it. How to state the state or condition when no products are available.
componentDidMount = () => {
this.setProducts();
// Gets all products in cart from localStorage
this.setState(
() =>{
return {cart: JSON.parse(localStorage.getItem('myCart'))}
},
() => {
this.addTotal()
})
// How to set the condition when no products in Cart?
}
// Set all the products on Main Page
setProducts = () => {
let tempProducts = [];
storeProducts.forEach(item => {
const singleItem = {...item};
tempProducts = [...tempProducts, singleItem];
});
this.setState(() => {
return {products: tempProducts};
});
};
// Here products are added to cart and stored in localStorage
addToCart = (id) => {
let tempProducts = [...this.state.products];
const index = tempProducts.indexOf(this.getItem(id));
const product = tempProducts[index];
product.inCart = true;
product.count = 1;
const price = product.price;
product.total = price;
this.setState(() => {
return { products: tempProducts, cart: [...this.state.cart,
product] };
},
() => {
this.addTotal();
localStorage.setItem('myCart', JSON.stringify(this.state.cart))
});
}
I have also tried to make following changes, but, no effect. In componentDidMount()
componentDidMount() {
if(this.state.cart.length > 0) {
this.setState(
() =>{
return {cart: JSON.parse(localStorage.getItem('myCart'))}
},
() => {
this.addTotal()
})
} else {
this.setState(() => {
return {cart:[]}
})
}
}
// Clear Cart
clearCart = () => {
this.setState(() => {
return {cart:[]}
}, () => {
this.setProducts();
this.addTotal();
})
localStorage.removeItem('myCart')
}
When I remove code of setState (shown in the beginning) from componentDidMount() displays empty cart message, which is expected else, if the cart is cleared and refreshed browser throws 'cart.length' error. Any possible solution?
JSON.parse will return an object. It depends on your data structure but there is no cart.lendth for the object. So that is your first problem. So for the below example, I store the parsed value as an array.
Also, if state.cart is not initiated, there is no .length property for it.
For your second problem have a look at the below version of your componentDidMount:
componentDidMount() {
if(Array.isArray(this.state.cart) && this.state.cart.length) {
const cart = localStorage.getItem('myCart') || [];
this.setState({cart: [JSON.parse(cart)]}), this.addTotal);
} else {
this.setState({ cart:[] });
}
}
Again, it depends on your implementation, but you might need to initiate the component's state with cart: localStorage.getItem('myCart') || [] or doing what I have done above. I'm basically checking if cart is an array && it has length then parse it otherwise initiate the array.
Finally I got the solution as below
const cart = localStorage.getItem('myCart')
this.setState({cart: JSON.parse(cart) ? JSON.parse(cart) : []}, this.addTotal)
Just modified the code and works perfectly without any issues

setState from .map inside componentDidMount()

I am trying to find a solution to using setState on mapped items inside componentDidMount.
I am using GraphQL along with Gatsby with many data items returned but require that on specific pathname is === to slug the state is updated in the component to the matching littleHotelierId.
propertyInit = () => {
const pathname = location.pathname;
return (
<StaticQuery
query={graphql`
query {
allContentfulProperties {
edges {
node {
id
slug
information {
littleHotelierId
}
}
}
}
}
`}
render={data => {
data.allContentfulProperties.edges.map(({ node: property }) => {
if (pathname === property.slug) {
!this.isCancelled &&
this.setState({
littleHotelierId: property.information.littleHotelierId
});
}
return null;
});
}}
/>
);
};
Then I am pulling this into componentDidMount as
componentDidMount() {
this.propertyInit();
}
not relevant but as reference this.isCancelled = true; is added to componentWillUnmount.
I don't receive any errors but if I console.log(littleHotelierId) I get nothing.
I did at first think that it may be because return is null so tried giving the map a const and returning as
render={data => {
data.allContentfulProperties.edges.map(({ node: property }) => {
if (pathname === property.slug) {
const littleHotelier =
!this.isCancelled &&
this.setState({
littleHotelierId: property.information.littleHotelierId
});
return littleHotelier;
}
});
}}
but this was unsuccessful too.
The Goal is for componentDidMount to map items returned in the GraphQL data as
componentDidMount() {
if (path1 === '/path-slug1') {
!this.isCancelled &&
this.setState({
littleHotelierId: 'path-id-1'
});
}
if (path2 === '/path-slug2') {
!this.isCancelled &&
this.setState({
littleHotelierId: 'path-id-2'
});
}
... // other items
}
I think the issue is that GraphQL is fetching data as asynchronous and this request not completed as componentDidMount() is called. If I console.log the data it is not returning anything to the console. How can I fix this?
I think you need to create some filtered data as a result of a map function. After you have filtered data you do setState({data: data}). It is not good to do multiple setState.
If your GraphQL returns promise then you can write something like the following:
componentDidMount() {
this.fetchData()
.then(data => {
const filteredData = data.filter(element =>
element.someProperty === propertyValue
);
this.setState({ data: filteredData });
})
}

Getting backend data in front reactJS

I am getting data from the backend to display it in the font like this
componentDidMount() {
const response = this.props.store.privateImputationData;
console.log(response);
}
It displays null in the console, now if i do a setTimeout it works!
componentDidMount() {
setTimeOut(() => {
const response = this.props.store.privateImputationData;
console.log(response);
}, 500);
}
This how i m getting data from my store:
#computed get ImputationData() {
return this.privateImputationData || {};
}
loadImputation = (diplayedImputations) => {
HttpClient.postJSON(this.apiDataUrl, diplayedImputations).then((result) => {
this.privateImputationData = result;
this.loadAdditionalData();
});
}
How can i do it without setTimeout?
You can use the state object: State and Lifecycle. Whenever the state changes, whatever component uses it, get's updated too.
this.state = {privateImputationData: null} //or some default
So in your code:
#computed get ImputationData() {
return this.privateImputationData || {};
}
loadImputation = (diplayedImputations) => {
HttpClient.postJSON(this.apiDataUrl, diplayedImputations).then((result) => {
this.setState({privateImputationData: result});
this.loadAdditionalData();
});
}
To use the value:
this.state.privateImputationData;

Categories

Resources