I'm trying to use a node server as the intermediary between firebase and my react native app.
Can someone please tell me what I'm doing wrong here with my fetch?
export const fetchPostsByNewest = () => {
return (dispatch) => {
fetch('http://localhost:3090/')
.then((response) => {
console.log(response.json());
//dispatch({ type: NEW_POSTS_FETCH_SUCCESS, payload: response.json()});
});
};
};
this is the node/express router:
const router = (app) => {
app.get('/', (req, res) => {
firebase.database().ref('/social/posts')
.once('value', snapshot => res.json(snapshot.val()));
});
};
If I console.log the response.json() then I just get this:
If I console.log response, I get this:
How can I get rid of the headers? If I do console.log(response._bodyInit) then I get this:
Which looks like what I need.
But if I pass it through as payload then I get this error:
My previous action creator directly worked with firebase, like this:
export const fetchPostsByNewest = () => {
return (dispatch) => {
firebase.database().ref('/social/posts')
.once('value', snapshot => {
console.log(snapshot.val())
dispatch({ type: NEW_POSTS_FETCH_SUCCESS, payload: snapshot.val() });
});
};
};
If I console.log(snapshot.val()). Then I got this:
This works just fine and looks the same as the last console.log of console.log(response._bodyInit).
What am I doing wrong here? I'd really appreciate any help.
Thank you!
response.json() returns a promise, so you need another link in the Promise chain
export const fetchPostsByNewest = () => {
return (dispatch) => {
fetch('http://localhost:3090/')
.then((response) => response.json())
.then((json) => {
console.log(json);
dispatch({ type: NEW_POSTS_FETCH_SUCCESS, payload: json});
});
};
};
If you don't need to console.log the json
export const fetchPostsByNewest = () => {
return (dispatch) => {
fetch('http://localhost:3090/')
.then((response) => response.json())
.then((json) => dispatch({ type: NEW_POSTS_FETCH_SUCCESS, payload: json}));
};
};
Fetch works a little different, when you call response.json() that returns another promise, so you need to chain another then after you return the new promise:
fetch('http://localhost:3090/')
.then(response => response.json())
.then(aFunctionToDoSomethingWithTheJson);
Related
I'm currently facing an issue where the data I receive from my Firebase database is not displaying in the function I need it to. The function I need the data in runs in useIonViewDidEnter/componentDidMount as I need it to begin polling when the page is entered and in an interval every 30 seconds.
I presume because it's run in the useIonViewDidEnter/componentDidMount the database is not retrieving the user's data in time before the function is run. I am wondering if anyone has any other suggestions on either getting the data earlier or taking the weather polling from the useIonViewDidEnter/componentDidMount elsewhere so the data is filled in time?
I get the data via the code below which also uses an interface User:
const [data, setData] = React.useState<User>();
useEffect(() => {
const userRef = db.collection('users').doc(currentUserID);
userRef.get().then((doc) => {setData(toUser(doc));})
}, [currentUserID])
But I need to access the data to request the weather:
useIonViewDidEnter(() => {
weatherInterval = setInterval(() => {
getWeather()
.then(data => setWeather(data.data))
.catch(error => {
setError(error)
return setShowError(true);
})
}, 30000);
}, );
const getWeather = () => {
setLoading(true);
return axios( {
url: `http://localhost:3000/weather`,
method: 'get',
}).then(res => {
setLoading(false);
console.log(res)
return res;
}).catch(error => {
return error
})
}
I figured it out. I replaced the useIonViewDidEnter() with useEffect() but I also had an issue with the intervals doubling up so I added in the following return statements:
return () => clearInterval(tempInterval);
The updated code to get it to work and get the database information is as followed:
useEffect(() => {
const userRef = db.collection('users').doc(currentUserID);
userRef.get().then((doc) => {
setData(toUser(doc));
})
}, [currentUserID])
useEffect(() => {
tempInterval = setInterval(() => {
sendGetRequest()
.then(data => setItems(data.temps))
.catch(error => {
if (error.response.status === 403) {
logout();
return error;
}
setError(error)
setShowError(true);
return error;
});
}, 30000);
return () => clearInterval(tempInterval);
})
useEffect(() => {
weatherInterval = setInterval(() => {
getWeather()
.then(data => setWeather(data.data))
.catch(error => {
setError(error)
return setShowError(true);
})
}, 30000);
return () => clearInterval(weatherInterval);
})
I have API on Node server returning JSON like this when called:
{"result":[{"ProductID":1,"ProductName":"iPhone10","ProductDescription":"Latest smartphone from Apple","ProductQuantity":100}]}
I'm trying to display all of that information to user using fetch API with React but no matter what my call returns undefined. Here is my React code:
const [products, setProducts] = useState({})
async function getProducts() {
await fetch(`http://127.0.0.1:5000/listProducts`)
.then(response => response.json())
.then(response=>{
setProducts({products:response.result})
console.log(response.result);
products.map(products =>
<h1>{products.ProductName}</h1>
<h1>{products.ProductDescription}</h1>
)
})
.catch(err=>console.error(err))
}
Function getProducts() is called once when page is loaded. What I'm doing wrong? Thanks in advance.
Try this it will work
const handleFetchData = async () => {
const response = await fetch(`https://api.unsplash.com/photos/random?client_id=${process.env.NEXT_PUBLIC_UNSPLASH_API_ACCESS_KEY}`);
const data = await response.json();
console.log(data);
}
useEffect(() => {
handleFetchData();
},[])
Your function is doing it wrong :
The name should be getAndSetProducts or even setProducts / initProducts because it returns a Promise<void> since you don't actually return anything ;
You're setting inside products an object { products: Product[] }, I think you want only Product[] (an array of Products) else you'll have to get products by doing products.products ;
The map is useless, since you don't do anything with the map response, plus the variable products in the map overwrite the one imported (may cause some errors later).
Try to do :
const [products, setProducts] = useState([]); // Array instead of object
async function initProducts() {
await fetch(`http://127.0.0.1:5000/listProducts`)
.then(response => response.json())
.then(response => {
setProducts(response.result);
console.log(response.result);
)
.catch(err => console.error(err));
}
function getProductsHtml() {
return products.map(product =>
<h1>{product.ProductName}</h1>
<h1>{product.ProductDescription}</h1>
);
}
You can call initProducts when component initialize and return getProductsHtml inside your jsx render.
Try this...
const [products, setProducts] = useState({})
React.useEffect(() => {
const fetchData = async () => {
const result = await fetch('http://127.0.0.1:5000/listProducts')
// console log here to determine how to set products
console.log(result)
setProducts(result)
}
fetchData()
}, [])
React.useEffect(() => {
if (!!products) {
// here you could access products!
}
}, [products])
if (!products) return null
return products.map((product) => (
<>
<h1>{products.ProductName}</h1>
<h1>{products.ProductDescription}</h1>
</>
))
If you are using Async, then you can use response.status as shown below
const response = await fetch("URL", {
body:BODY_DATA,
method:'POST',
headers: { "Content-Type": "application/json"
});
if(response.status === 200){
// Complete your action
} else {
// Show error
}
you can't use async await with .then() you should only use async await or .then() only
I've build a function to make an api call to a weather service and then update state based on if it resolves, or rejects. The code works perfectly, but it feels messy to me.
getForecastedWeather(){
const endpoint = `http://dataservice.accuweather.com/forecasts/v1/daily/5day/207931?apikey=mG0ISFW1ZGGHIV3rs5CSFQlF92CYSqhr&language=en&details=true&metric=true`;
const fetchPromise = fetch(endpoint);
fetchPromise
.then(response => response.json())
.then(result => {
this.setState(state => ({
forecasts: {
...state.forecasts,
error: null,
isLoaded:true,
forecasts:result.DailyForecasts
},
}));
}).catch(error => {
this.setState(state => ({
forecasts: {
...state.forecasts,
error,
isLoaded:false
},
}));
})
}
Is there a better way of handling this?
Please consider using async await syntax:
async getForecastedWeather(){
try {
const endpoint = `http://...`;
const response = await fetch(endpoint);
const result = await response.json();
this.setState(state => ({ ... }));
} catch (error) {
this.setState(state => ({ ... }));
}
}
i have a problem:
I want that my axios make the requistion and after it makes the this.setState with the result saved in a variable.
My code:
componentDidMount() {
let mails = [];
axios.get('/api/employee/fulano')
.then(res => this.setState({
employees: res.data
}, () => {
this.state.employees.map(i => {
async axios.get(`/api/status/${i.mail}`)
.then(res => {
mails.push(res.data)
await this.setState({
mails: mails
})
})
.catch(err => console.log(err))
})
}))
.catch(err => console.log(err))
}
But it gives error syntax.
Best explanation: I want saved all results of the map in the variable mails and later to use the setState to changes the result of just a time.
Someone could tell me where i'm wandering? Please.
You are using async await at the wrong places. async keyword must be used for a function that contains asynchronous function
await keyword needs to be used for an expression that returns a Promise, and although setState is async, it doesn't return a Promise and hence await won't work with it
Your solution will look like
componentDidMount() {
let mails = [];
axios.get('/api/employee/fulano')
.then(res => this.setState({
employees: res.data
}, async () => {
const mails = await Promise.all(this.state.employees.map(async (i) => { // map function contains async code
try {
const res = await axios.get(`/api/status/${i.mail}`)
return res.data;
} catch(err) {
console.log(err)
}
})
this.setState({ mails })
}))
.catch(err => console.log(err))
}
It's not a good practice to mix async/await with .then/.catch. Instead use one or the other. Here's an example of how you could do it using ONLY async/await and ONLY one this.setState() (reference to Promise.each function):
componentDidMount = async () => {
try {
const { data: employees } = await axios.get('/api/employee/fulano'); // get employees data from API and set res.data to "employees" (es6 destructing + alias)
const mails = []; // initialize variable mails as an empty array
await Promise.each(employees, async ({ mail }) => { // Promise.each is an asynchronous Promise loop function offered by a third party package called "bluebird"
try {
const { data } = await axios.get(`/api/status/${mail}`) // fetch mail status data
mails.push(data); // push found data into mails array, then loop back until all mail has been iterated over
} catch (err) { console.error(err); }
})
// optional: add a check to see if mails are present and not empty, otherwise throw an error.
this.setState({ employees, mails }); // set employees and mails to state
} catch (err) { console.error(err); }
}
This should work:
componentDidMount() {
axios.get('/api/employee/fulano')
.then(res => this.setState({
employees: res.data
}, () => {
this.state.employees.map(i => {
axios.get(`/api/status/${i.mail}`)
.then( async (res) => { // Fix occurred here
let mails = [].concat(res.data)
await this.setState({
mails: mails
})
})
.catch(err => console.log(err))
})
}))
.catch(err => console.log(err))
}
You put async in the wrong place
async should be placed in a function definition, not a function call
componentDidMount() {
let mails = [];
axios.get('/api/employee/fulano')
.then(res => this.setState({
employees: res.data
}, () => {
this.state.employees.map(i => {
axios.get(`/api/status/${i.mail}`)
.then(async (res) => {
mails.push(res.data)
await this.setState({
mails: mails
})
})
.catch(err => console.log(err))
})
}))
.catch(err => console.log(err))
}
i'm trying to assign the variable countries to the response of the fetch api but when i print out countries i get undefined ? can anyone explain to me why ? and a solution if it is possible.
async function getCountries(url) {
const data = await fetch(url);
const response = await data.json();
return response;
}
let countries;
document.addEventListener('DOMContentLoaded', () => {
getCountries('https://restcountries.eu/rest/v2/all')
.then(res => countries = res)
.catch(err => console.log(err));
})
console.log(countries);
function getCountries(url) {
return new Promise((resolve,reject)=>{
fetch(url).then(res => {
//You can parse the countries from the api response here and return to the
//event listener function from here using the resolve methood call parameter
resolve(res);
})
.catch(err => console.log(err));
})
}
document.addEventListener('DOMContentLoaded', () => {
getCountries('https://restcountries.eu/rest/v2/all')
.then(res => {
//the returned value after api call and parsing will be available here in res
})
})
Or if you dont want another function for this one you can directly get it using the following way,
document.addEventListener('DOMContentLoaded', () => {
let countries;
fetch('https://restcountries.eu/rest/v2/all')
.then(res => {
//the returned value after api call and parsing out the countries hereit self
countries = res.data.countries;
})
})