I am trying to set the state inside of a firebase snapshot function but I am getting an Cannot read property 'setState' of null error. I am not sure how to make it work.
This is my code:
componentDidMount = () => {
const dataGoalRef = dbRef.child('goals/'+this.state.uid);
dataGoalRef.child("mainGoal").on("value", function(mainGoalKeySnapshot) {
var favoriteMainGoal = mainGoalKeySnapshot.val();
console.log(favoriteMainGoal);
var queryRef = dataGoalRef.orderByKey().equalTo(favoriteMainGoal);
queryRef.on("value", snap => {
this.setState({
dataGoal: snap.val(),
});
});
});
}
How can I do so?
I've just figured it out. I wasn't binding the first method. So the solution is:
componentDidMount = () => {
const dataGoalRef = dbRef.child('goals/'+this.state.uid);
dataGoalRef.child("mainGoal").on("value", (mainGoalKeySnapshot) => {
var favoriteMainGoal = mainGoalKeySnapshot.val();
console.log(favoriteMainGoal);
var queryRef = dataGoalRef.orderByKey().equalTo(favoriteMainGoal);
queryRef.on("value", snap => {
this.setState({
dataGoal: snap.val(),
});
});
});
}
Try by using arrow function instead of normal function declaration for callback which you have passed in dataGoalRef.child("mainGoal").on("value", function(mainGoalKeySnapshot){})
updated code
dataGoalRef.child("mainGoal").on("value", (mainGoalKeySnapshot) => {
....
....
});
Related
I'm trying to use file upload with preview and this is the code of my component:
const [uploadField, setUploadFiled] = useState()
useEffect(() => {
const temp = new FileUploadWithPreview('fileUpload', {
multiple: multiple,
});
window.addEventListener(Events.IMAGE_ADDED, (e) => {
const { detail } = e;
console.log('detail', detail);
});
}, [])
The problem is that since I have <React.StrictMode> I see two file upload controls in my page. And whenever I save the file, because of HMR another control would be created.
I want to only run that initialization code once.
How can I achieve that?
You can use the useRef hook to store a reference to the FileUploadWithPreview instance.
This will ensure that the code is only executed once, even when HMR is enabled.
const uploadFieldRef = useRef();
useEffect(() => {
const temp = new FileUploadWithPreview('fileUpload', {
multiple: multiple,
});
uploadFieldRef.current = temp;
window.addEventListener(Events.IMAGE_ADDED, (e) => {
const { detail } = e;
console.log('detail', detail);
});
}, []);
try useRef hook
const effectCalled = useRef(false);
useEffect(() => {
if (effectCalled.current) return;
console.log("app rendered");
effectCalled.current = true;
}, []);
Everyone does a weather app for api practice so I decided to do something different I'm using Pokeapi to make a small app. I have to call a few different apis to make it work how I want which is being done like this
const api = "https://pokeapi.co/api/v2/pokemon";
const apiMoves = "https://pokeapi.co/api/v2/move";
const apiSpecies = "https://pokeapi.co/api/v2/pokemon-species"
const searchBox = document.querySelector(".search-box");
searchBox.addEventListener("keypress", setQuery);
function setQuery(e) {
if (e.keyCode == 13) {
getResults(searchBox.value);
searchBox.value = "";
}
}
function getResults(query) {
const pokemonData = fetch(`${api}/${query}`)
.then((data) => {
return data.json();
});
pokemonData.then(displayResults)
pokemonData.then(data => {
return fetch(`${apiMoves}/${data.moves[0].move.name}`)
.then(data => data.json())
.then(move => {
console.log(move)
})
})
pokemonData.then(data => {
return fetch(`${apiSpecies}/${query}`)
.then(data => data.json())
.then(species => {
console.log(species)
})
})
}
all 3 of the end points are being logged in the console so I can see them. However looking at api call 2 I'm passing info from the first api call to get more info and that logs fine. When I'm trying to display the info from that 2nd api call it just returns undefined but in the console I can see all the endpoints.
the display results looks something like this.
function displayResults(pokemon) {
let name = document.querySelector('h2')
name.innerText = pokemon.name <-- this works.
let dmg1 = document.querySelector('.dmg1')
dmg1.innerText = pokemon.power <-- this is returning undefined but in the console "power" shows a number.
}
I've tried to replace the pokemon.power with move.power but that gives an error saying "move" is not defined.
I'm thinking that I'm simply calling the 2nd and 3rd api wrong? I'm not sure and trying to search for this issue is a bit rough.
any help is appreciated!
const pokeApiPrefix = 'https://pokeapi.co/api/v2/';
const apiPokemon = `${pokeApiPrefix}pokemon`;
const apiMoves = `${pokeApiPrefix}move`;
const apiSpecies = `${pokeApiPrefix}pokemon-species`;
const searchBox = document.querySelector('.search-box');
searchBox.addEventListener('keypress', setQuery);
function setQuery(e) {
if (e.keyCode == 13) {
getResults(searchBox.value.toLowerCase());
searchBox.value = '';
}
}
getResults('Dragonite'.toLowerCase());
function getResults(pokemon) {
let dmg1 = document.querySelector('.dmg1');
dmg1.innerText = `Getting results. Please wait...`;
const pokemonData = fetch(`${apiPokemon}/${pokemon}`)
.then((data) => data.json())
.then((data) => {
console.log(`pokemon data:`, data);
displayPokemonName(data);
const moveName = data.moves[0].move.name;
return fetch(`${apiMoves}/${moveName}`);
})
.then((data) => {
return data.json();
})
.then((data) => {
displayMovePower(data);
console.log(`move data:`, data);
return fetch(`${apiSpecies}/${pokemon}`);
})
.then((data) => data.json())
.then((data) => {
console.log(`species data:`, data);
});
}
// function displayResults(pokemon) {
// let name = document.querySelector('h2');
// name.innerText = pokemon.name;
// let dmg1 = document.querySelector('.dmg1');
// // I couldn't find 'power' attribute on api results, used id instead
// // https://pokeapi.co/docs/v2#pokemon
// dmg1.innerText = `#${pokemon.id}`;
// }
function displayPokemonName(pokemon) {
let name = document.querySelector('h2');
name.innerText = `Pokemon name: ${pokemon.name}`;
}
function displayMovePower(move) {
let dmg1 = document.querySelector('.dmg1');
dmg1.innerText = `Move power: ${move.id}`;
}
<input type="text" class="search-box" />
<h2></h2>
<div class="dmg1"></div>
I've created a snippet, chaining multiple promises and logging every result on the console.
As stated, it seems you are trying to use an attribute 'power', which is not present in the first pokemon api call
Here this line is not working because you are trying to access the attribute which does not exist in the object.
let dmg1 = document.querySelector('.dmg1')
dmg1.innerText = pokemon.power <-- this is returning undefined but in the console "power" shows a number.
What might work for you is:
dmg1.innerText = pokemon.moves[0].move.name
I have the following json structure:
Within "all" node I have an attribute "drinkId" and I'm trying to move it outside that child node bringing it one level up.
I'm trying to read the value without any luck
const cocktailRef= firebase
.database()
.ref("Ratings");
cocktailRef.once("value", (snapshot) => {
snapshot.forEach((child) => {
const drinkIdPass = child.ref.child("all").child("drinkId").value();
child.ref.update({ drinkId: drinkIdPass });
})
})
I've tried different variants of ".value()", same problem
There isn't any value() method on a DataSnapshot. It's val() Try refactoring your code like this:
const cocktailRef= firebase.database().ref("Ratings");
cocktailRef.once("value").then(async (snapshot) => {
const updates = { }
snapshot.forEach((child) => {
const drinkIdPass = child.val().all.drinkId
updates[`${child.key}/drinkId`] = drinkIdPass
})
await cocktailRef.update(updates)
console.log("Data updated")
})
I'm trying to build a very simple app for searching articles and using the localstorage to display more info about each article but when I set to save into the session storage for some reason is saving the initial or previous state, I assume because I need to set async for this but I just can't figure how
This is how I have it right now, findArticleQuery() is called on the handleSubmit
useEffect(
() =>{
findArticlesQuery();
} ,[]
)
const findArticlesQuery = (query) => { //search function
axios.get(`url`)
.then(res => {
[res.data].map((val) =>(
setState(val)
))
}).catch(error => {
console.log(error.response)
});
}
const handleSubmit = (e) => {
e.preventDefault();
findArticlesQuery(e.target.search.value)
sessionStorage.setItem('localData', JSON.stringify(state)) //<--here I get the value of the previous state
e.target.search.value = '';
}
I need to use the session storage because I will have a detailed article component page.
Thank you guys!
You can get search result from findArticlesQuery() like below.
...
const findArticlesQuery = (query) => { //search function
return axios.get(`url`)
.then(res => {
setState(res.data)
return res.data
})
}
const handleSubmit = (e) => {
e.preventDefault();
findArticlesQuery(e.target.search.value)
.then(val => sessionStorage.setItem('localData', JSON.stringify(val)))
e.target.search.value = '';
}
For saving state in the localStorage with React Hooks, something I've been using and that is extremely convenient is useLocalStorage.
Disclaimer : I am not the creator of this lib.
I am trying to query a value from a document in collection, in fire base, particularly "currentKilos":
I am using the below function to query it:
showKiols = () => {
db.collection('users').doc(this.props.user.uid).collection('mainData').doc('currentKilos').get().then.subscribe(value=> {
this.updatedKilos = value;
alert(this.updatedKilos);
})
}
However, I am getting attached error:
Also, I tried below function as well, but it is not working:
db.collection('users').doc(this.props.user.uid).collection('mainData').doc('currentKilos').valueChanges().subscribe(value => {
this.updatedKilos = value.currentKilos;
alert(this.updatedKilos)
})
FYI, this is the function to add currentKilos to firebase, and it is working fine:
updateKilos = () => {
db.collection('users').doc(this.props.user.uid).collection('mainData').doc('currentKilos').set({ currentKilos: this.state.currentKilos })
alert('Data Updated')
}
Appreciate your support.
I'm not sure where you get get().then.subscribe() from, but at the very least that then should be then((value)=>{...}).
Try the following:
showKiols = () => {
db.collection('users')
.doc(this.props.user.uid)
.collection('mainData')
.doc('currentKilos')
.get()
.then(value => {
this.updatedKilos = value.data();
alert(this.updatedKilos);
})
}