hello im new to react and trying to build a weather site. i have a search functionality which works, but im also trying to get the local weather for the user.
for this i get city from: https://geoip-db.com/json/
weather api: https://api.openweathermap.org/data/2.5/
then i save that city as a variable in the state so i can use it in the api.
here is the code:
`
state = {
geoipCity: "",
}
componentDidMount(){
const geoApiUrl = "https://geoip-db.com/json/";
fetch(geoApiUrl)
.then(res => res.json())
.then(geoip => {
this.setState({ geoipCity: geoip.city })
})
.catch(err => {
console.log("Fetch error: " + err);
});
console.log("prefetch:" + this.state.geoipCity)
const weatherApiUrl = `${api.base}weather?q=${this.state.geoipCity}&weather&units=metric&APPID=${api.key}`;
fetch(weatherApiUrl)
.then(res => res.json())
.then(result => {
console.log(result)
let locationOutput = document.querySelector("#locationOutput");
if(result.cod === "404"){
locationOutput.innerHTML = `${this.state.geoipCity} is not a valid city name`;
}
/*
locationOutput.innerHTML = `
Your live in ${this.state.geoipCity} and it feels like ${result.main.feels_like}°C`;
*/
})
.catch(err => {
console.log("Fetch error: " + err);
});
}
`
so the first fetch gets the city and saves it in the geoipCity state variable. this i try to use it in the api search.
however right before that i have:
console.log("prefetch:" + this.state.geoipCity)
which shows me that this.state.geoipCity is empty.
any ideas?
EDIT: SOLVED, HERE IS THE CODE IN CASE ANYONE BENEFITS FROM IT IN THE FUTURE
`
componentDidMount(){
const geoApiUrl = "https://geoip-db.com/json/";
fetch(geoApiUrl)
.then(res => res.json())
.then(result => {
console.log(result)
this.setState({ geoipCity: result.city }, () => {
//console.log(this.state);
const weatherApiUrl = `${api.base}weather?q=${this.state.geoipCity}&weather&units=metric&APPID=${api.key}`;
fetch(weatherApiUrl)
.then(res => res.json())
.then(result => {
console.log(result)
let locationOutput = document.querySelector("#locationOutput");
if(result.cod === "404"){
locationOutput.innerHTML = `${this.state.geoipCity} is not a valid city name`;
}
locationOutput.innerHTML = `
Your live in ${this.state.geoipCity} and it feels like ${result.main.feels_like}°C`;
})
.catch(err => {
console.log("Fetch error: " + err);
});
});
//this.setState({ geoipCity: geoip.city })
})
.catch(err => {
console.log("Fetch error: " + err);
});
}
`
this.setState is async.
You need to use the callback of setState in order to console.log the new state.
this.setState({ geoipCity: geoip.city }, (newState) => {
console.log(newState);
});
Every setState will re-render the component but componentDidMount only executes on the first render.
Related
I'm new to javascript and there's a problem I'm not all able to solve.
I have one array of objects, which contains 2 attributes. I want to connect the attributes, one of which will be a key and the other will be a value.
this is what I have:
[{"prefer":"code_html","rating":"5"},{"prefer":"code_css","rating":"3"}]
This is what I want to get:
[
{
"code_html": "5"
},
{
"code_css": "3"
}
]
I run this function:
const array = [{"prefer":"code_html","rating":"5"},{"prefer":"code_css","rating":"3"}]
const result = array.map(({prefer, rating}) => ({[prefer]: rating}));
console.log(result);
But I can not understand why it does not work for me.
This is the print I get, I do not understand what is wrong
[{},{},{}]
I use this code in nodeJs, maybe that's why I have a problem:
exports.addUserKmeansMatchVer2 = (req, res) => {
console.log("addUserKmeansMatch function filter:");
arr = [];
if(req.query.filterArray)
{
arr = [...req.query.filterArray];
console.log("line 256" + typeof(req.query.filterArray));
//this is print line 256object
console.log("line 257" +arr);
//this is works prints: line 257{"prefer":"sport_swimming","rating":"3"},{"prefer":"code_html","rating":"5"},{"prefer":"code_css","rating":"3"}
console.log("line 258" + req.query.filterArray);
//print exactly the same as line 257
}
let onlyPreferencesAllow = [];
arr.forEach(({prefer,rating}) => onlyPreferencesAllow.push({[prefer]: rating}));
console.log("line 262" + JSON.stringify(onlyPreferencesAllow));
//this is NOT work prints: line 262[{},{},{}]
db.doc(`/match/${req.user.handle}`)
.set("testing")
.then(() => {
return res.json({ message: "Details added successfully" });
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
}
})
})
};
I noticed that in line 257 it prints for me without the parentheses of the array without [], but in line 262 it prints with the parentheses [], I do not quite understand it
I thought of something I forgot to mention,
I get the req.query.filterArray, through the params.
Here's how I do it:
export const makeMatchVer2 = (data) => (dispatch) => {
dispatch({ type: LOADING_DATA });
axios
.get('/kmeansFilter', {
params: {
filterArray: data
}
})
.then((res) => {
dispatch({
type: MAKE_MATCH,
payload: res.data
});
})
.catch((err) => {
dispatch({
type: MAKE_MATCH,
payload: []
});
});
};
the data itself is an array, maybe here i do the mistake
The solution that worked for me:
When I send an array in params to api, I need to use JSON.stringify.
export const makeMatchVer2 = (data) => (dispatch) => {
dispatch({ type: LOADING_DATA });
axios
.get('/kmeansFilter', {
params: {
filterArray: JSON.stringify(data)
}
})
.then((res) => {
dispatch({
type: MAKE_MATCH,
payload: res.data
});
})
.catch((err) => {
dispatch({
type: MAKE_MATCH,
payload: []
});
});
};
And when I get the answer in nodeJS, I have to use JSON.parse
exports.addUserKmeansMatchVer2 = (req, res) => {
console.log("addUserKmeansMatch function filter:");
arr = [];
if(req.query.filterArray)
{
arr = JSON.parse(req.query.filterArray);
}
let onlyPreferencesAllow = [];
arr.forEach(({prefer,rating}) => onlyPreferencesAllow.push({[prefer]: rating}));
console.log("line 262" + JSON.stringify(onlyPreferencesAllow));
db.doc(`/match/${req.user.handle}`)
.set("testing")
.then(() => {
return res.json({ message: "Details added successfully" });
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
}
})
})
};
It's kinda working,but problem is it copies the file which is being updated and puts it in the end of page,All I'm trying to do display update on the item
Here what I'm trying to do
submitEdit = (id, value) => {
let {todos} = this.state
todos.map((item => {
if (item._id === id) {
axios
.put(`http://localhost:8080/edit/${id}`, {
todo: value,
})
.then((res) => {
this.setState({
todos:[...todos,{todo:value}]
})
console.log("res", res);
})
.catch((err) => {
console.log("err", err);
});
}
}))
}
beside this everything is working fine
You need to update the state by using the index so that the todo element is updated and not copied and added to the end
You can use Array.prototype.slice with spread syntax to do that
todos.map(((item, i) => {
if (item._id === id) {
axios
.put(`http://localhost:8080/edit/${id}`, {
todo: value,
})
.then((res) => {
this.setState({
todos:[...todos.slice(0, i),{todo:value}, ...todos.slice(i + 1)]
})
console.log("res", res);
})
.catch((err) => {
console.log("err", err);
});
}
}))
I need to register a new user, when receiving the parameters make a query using the city name to get the state and city id (both are foreign keys). I implemented a function to find the ids. Inside the function using data.id the id is returned correctly. But at the time of insert in database is being inserted "undefined".
Apparently the save operation is being executed before the findCity and findState functions return the value.
execution flow
cidade = city, estado = city
module.exports = app => {
const obterHash = (senha, callback) => {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(senha, salt, null, (err, hash) => callback(hash))
})
}
var idCidade;
var idEstado
function findCidade(cidade, ) {
app.db('cidades')
.where({ nome: cidade })
.first()
.then(data => {
idCidade = data.id
console.log('inside findCity. data.id: '+data.id)
}).catch((err) => console.log("erro cidade", err));
return
}
function findEstado(uf) {
app.db('estados')
.where({ uf: uf })
.first()
.then(data => {
idEstado = data.id
console.log('inside findState. data.id: '+data.id)
}).catch((err) => console.log("erro estado", err));
}
const save = (req, res) => {
console.log("\n")
findCidade(req.body.cidade)
findEstado(req.body.uf)
obterHash(req.body.senha, hash => {
const senha = hash
console.log("Will be inserted. idCity: "+idCidade+" idState: "+idEstado)
app.db('salao')
.insert({ idcidade: idCidade,
idestado: idEstado,
senha})
.then(_ => res.status(200).send())
.catch(err =>{res.status(400).json(err)})
})
}
return { save }
}
I'm from Brazil and I'm using a translator, sorry for the spelling mistakes.
You are welcome to the asynchronous world!
General explanation: You are going to use results of a database querying before it will happen. Your program have to wait the results (idCidade, idEstado) before you can use it. Because of it you can find the record Will be inserted... first in your logs.
For the explanation I'm going to use Minimal Reproducible Example.
function findCidade(cidade) {
return Promise.resolve(1);
}
function findEstado(uf) {
return Promise.resolve(1);
}
Promise.all([findCidade(), findEstado()])
.then((data) => console.log(data));
The output is:
[ 1, 1 ]
To solve the issue you have to:
Return the promise explicitly with return statement.
Await the results by async/await or Promise interface methods. Or use callbacks if it is more suitable to you.
module.exports = app => {
const obterHash = (senha, callback) => {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(senha, salt, null, (err, hash) => callback(hash))
})
};
function findCidade(cidade, ) {
return app.db('cidades')
.where({ nome: cidade })
.first()
.then(data => {
idCidade = data.id
console.log('inside findCity. data.id: '+data.id)
}).catch((err) => console.log("erro cidade", err));
}
function findEstado(uf) {
return app.db('estados')
.where({ uf: uf })
.first()
.then(data => {
idEstado = data.id
console.log('inside findState. data.id: '+data.id)
}).catch((err) => console.log("erro estado", err));
}
const save = (req, res) => {
console.log("\n");
Promise.all([findCidade(req.body.cidade), findEstado(req.body.uf)])
.then((data) => {
const [idCidade, idEstado] = data;
obterHash(req.body.senha, hash => {
const senha = hash;
console.log("Will be inserted. idCity: "+idCidade+" idState: "+idEstado);
app.db('salao')
.insert({ idcidade: idCidade,
idestado: idEstado,
senha})
.then(_ => res.status(200).send())
.catch(err =>{res.status(400).json(err)})
})
})
.catch((err) => console.log("general error", err));
};
return { save }
}
I have an Express backend server on port 5000 and react front end running on port 3000. I am trying to fetch some data from express post route and return it to front end but my Promise never resolves. It always ends up as "stalled".
util.inspect(messageList) shows my array on server console but my Promise on the front end never resolves.
I'm fetching some data server side on ComponentDidMount like below:
class Conversation extends React.Component {
state = {
conversations: [],
messages: [],
error: null,
loading: true,
input: '',
owner: 'Unassigned'
}
componentDidMount() {
const { match } = this.props
const { conversationId } = match.params
// Make a POST request to our server and pass the conversationId
this.getMessages(conversationId)
}
getMessages(conversationId) {
return fetch('/search-conversation', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ conversation: conversationId })
})
.then(res => res.json())
.then((messages) => this.setState({ messages }))
}
Server Side:
app.post('/search-conversation', (req, res) => {
conversationId = req.body.conversation
if (!conversationId) {
res.send('/error');
} else {
console.log(`Success, conv id is ${conversationId}`);
}
// call function to go get messages from API
console.log(`fetching messages for ${conversationId}`)
return fetch(endpoint)
.then((res) => res.json())
.then(({ data }) => data)
.then((data) => {
const messageList = data[0].messages.data
return messageList
})
.then((messageList) => console.log(util.inspect(messageList)))
.catch(error => console.error(`Error: ${error}`))
});
Any ideas are appreciated, thanks in advance.
You are missing res.json() call on the server side that will send response to the client:
app.post('/search-conversation', (req, res) => {
conversationId = req.body.conversation
if (!conversationId) {
res.send('/error');
} else {
console.log(`Success, conv id is ${conversationId}`);
}
// call function to go get messages from API
console.log(`fetching messages for ${conversationId}`)
return fetch(endpoint)
.then((res) => res.json())
.then(({ data }) => data)
.then((data) => {
const messageList = data[0].messages.data
res.json(messageList) // <-- sending response
})
.catch(error => console.error(`Error: ${error}`))
});
I'm trying to save data into Firebase storage.
Generally, my method and function works, in FireBase logs I get:
Function execution took 1442 ms, finished with status code: 201
alert15
alert14: null||[object Object]
alert12:
alert11:
Billing account not configured. External network is not accessible and quotas are severely limited. Configure billing account to remove
these restrictions
Function execution started
My function:
const functions = require('firebase-functions');
const cors = require("cors")({origin: true});
const fs = require("fs");
const UUID = require("uuid-v4");
const gcconfig = {
projectId: "myrojectid",
keyFilename: "mykeyfile.json"
};
const gcs = require("#google-cloud/storage")(gcconfig);
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
exports.storeImage = functions.https.onRequest((request, response) => {
console.log("alert11: ")
cors(request, response, () => {
console.log("alert12: ")
const body = JSON.parse(request.body);
fs.writeFileSync("/tmp/uploaded-image.jpg", body.image, "base64", err => {
console.log(err => console.log("alert13: " + err));
return response.status(500).json({error: err})
});
const bucket = gcs.bucket("myapp.appspot.com");
const uuid = UUID();
bucket.upload(
"/tmp/uploaded-image.jpg",
{
uploadType: "media",
destination: "/places2/" + uuid + ".jpg",
metadata: {
metadata: {
contentType: "image/jpeg",
firebaseStorageDownloadTokens: uuid
}
}
}, (err, file) => {
console.log("alert14: " + err + "||" + file)
if (!err) {
console.log("alert15");
response.status(201).json({
imageUrl:
"https://firebasestorage.googleapis.com/v0/b/" +
bucket.name +
"/o/" +
encodeURIComponent(file.name) +
"?alt=media&token=" +
uuid
})
} else {
console.log("alert16: ")
console.log(err);
response.status(500).json({error: err})
}
});
});
});
My method:
import {ADD_PLACE, DELETE_PLACE} from './actionTypes';
export const addPlace = (placeName, location, image) => {
return dispatch => {
fetch("https://us-central1-myapp.cloudfunctions.net/storeImage", {
method: "POST",
body: JSON.stringify({
image: image.base64
})
})
.catch(err=> console.log(err))
.then(res => {res.json(); console.log("alert2 " + {res})})
.then(parsedRes => {
console.log("alert1: " + parsedRes);
const placeData = {
name: placeName,
location: location,
image: parsedRes.imageUrl
};
return fetch("https://myapp.firebaseio.com/places.json", {
method: "POST",
body: JSON.stringify(placeData)
}).catch(err => console.log("alert13: " + err))
})
.catch(err => console.log("alert4", err))
.then(res => res.json())
.catch(err => console.log("alert5: " + err))
.then(parsedRes => {
console.log("alert6", parsedRes);
}).catch(err => console.log("alert17: " + err));
};
};
export const deletePlace = (key) => {
return {
type: DELETE_PLACE,
placeKey: key
};
};
but in local console in my IDE I got this:
alert1: undefined
'alert4', { [TypeError: undefined is not an object (evaluating 'parsedRes.imageUrl')]
I wasted 3 days for this and still 0 progress.
What can be wrong here ? How to fix it ?
You're not using promise chaining correctly. You need to explicitly return the result of a then() callback to the next handler in the chain. Without returning anything, the next then() callback will get undefined. For example:
.then(res => {res.json(); console.log("alert2 " + {res})})
In this line of code, you're not returning anything to pass along to the next handler in the chain.
In fact, the above then() callback is unnecessary because it's not kicking off any other async work. You could just call res.json() in the subsequent then() block, just before the second fetch. You typically only add another then() block when you have more async work to do as a result of the prior async work.