Update one property in MongoDB and update UI without refresh the page - javascript

I am trying to update one property Like I have a few properties, product name, price, quantity, supplier, and description. I am sending all the updated quantities with all properties to MongoDb, in that case, I am able to update the database and UI without any refresh.
const handleDelivered = (id) => {
const newQuantity = (quantity - 1);
if (newQuantity >= 0) {
const newService = {...serviceDetail, quantity: newQuantity}
setServiceDetail(newService);
const url = `https://intense-tor-77999.herokuapp.com/item/${id}`;
fetch(url, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newService),
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
})
}
else{
toast(`${productName} is sold out`);
}
}
But I just want to update only one property for example only quantity like
const updateQuantity = { quantity : newQuantity};
So, how can I update this one property without sending all properties from my frontend to backend?

Firstly you can declare
const [isReload, setIsReload]= useState(true);
when you get response from database after uploading new quantity, add this
.then(response => response.json())
.then(data => {
console.log('Success:', data);
setIsReload(!isReload);
});
than you put isReload as dependency of useEffect, where you load data by id
useEffect(()=>{
fetch(url)
.then(res=>res.json())
.then(data => setData(data))
},[isReload ]);
try it

Related

How to treat JSON data in React?

I am using the following code using a flight data API:
useEffect(() => {
fetch(url, options)
.then((res) => res.json())
.then((json) => {
console.log(json);
datos.push(json)
})
.catch((err) => console.log('error' + err));
}, []);
return (
<div className='ejemplo'>
{JSON.stringify(datos)}
<div\>
)
and this is the result in the DOM:
[{"success":true,"data":{"2023-02-08":{"origin":"MAD","destination":"BCN","price":88,"airline":"UX","flight_number":7701,"departure_at":"2023-02-08T07:30:00+01:00","return_at":"2023-02-12T11:50:00+01:00","transfers":0,"expires_at":"2023-02-07T08:27:20Z"},"2023-02-09":{"origin":"MAD","destination":"BCN","price":69,"airline":"IB","flight_number":3034,"departure_at":"2023-02-09T21:15:00+01:00","return_at":"2023-02-13T18:05:00+01:00","transfers":0,"expires_at":"2023-02-07T08:27:20Z"},"2023-02-14":{"origin":"MAD","destination":"BCN","price":69,"airline":"IB","flight_number":3012,"departure_at":"2023-02-14T11:30:00+01:00","return_at":"2023-02-18T21:05:00+01:00","transfers":0,"expires_at":"2023-02-07T08:27:20Z"},"2023-02-15":{"origin":"MAD","destination":"BCN","price":69,"airline":"IB","flight_number":3034,"departure_at":"2023-02-15T21:15:00+01:00","return_at":"2023-02-19T14:30:00+01:00","transfers":0,"expires_at":"2023-02-07T08:27:20Z"},"2023-02-16":{"origin":"MAD","destination":"BCN","price":87,"airline":"IB","flight_number":3018,"departure_at":"2023-02-16T16:00:00+01:00","return_at":"2023-02-20T12:35:00+01:00","transfers":0,"expires_at":"2023-02-07T08:27:20Z"},"2023-02-17":{"origin":"MAD","destination":"BCN","price":57,"airline":"IB","flight_number":5003,"departure_at":"2023-02-17T22:20:00+01:00","return_at":"2023-02-21T20:30:00+01:00","transfers":0,"expires_at":"2023-02-07T08:27:20Z"},"2023-02-19":{"origin":"MAD","destination":"BCN","price":63,"airline":"UX","flight_number":7701,"departure_at":"2023-02-19T07:30:00+01:00","return_at":"2023-02-23T20:30:00+01:00","transfers":0,"expires_at":"2023-02-07T08:27:20Z"},"2023-02-21":{"origin":"MAD","destination":"BCN","price":69,"airline":"IB","flight_number":3012,"departure_at":"2023-02-21T11:30:00+01:00","return_at":"2023-02-25T14:30:00+01:00","transfers":0,"expires_at":"2023-02-07T08:27:20Z"},"2023-02-23":{"origin":"MAD","destination":"BCN","price":52,"airline":"UX","flight_number":7701,"departure_at":"2023-02-23T07:30:00+01:00","return_at":"2023-02-27T11:50:00+01:00","transfers":0,"expires_at":"2023-02-07T08:27:20Z"}
How can I modify my code in order to obtain just the origin, destination and price attributes? Thanks you all.
I tried to add a . plus the search attributes but no correct response was given.
You can loop your data by key and create a custom array of objects:
const [datos, setDatos] = useState([]);
useEffect(() => {
fetch(url, options)
.then((res) => res.json())
.then((json) => {
const { success, data } = json;
if (!success) console.log(error);
else {
const dataList = [];
for (const key in data) {
const { origin, destination, price } = data[key];
dataList.push({ origin, destination, price });
}
setDatos(dataList);
}
})
.catch((err) => console.log('error' + err));
}, []);
return (
<div className='ejemplo'>
{
datos.length > 0 && datos.map((d, index) => {
return <div key={index}>
<p>{d.origin}</p>
<p>{d.destination}</p>
<p>{d.price}</p>
</div>
}
}
</div>
)
You can extract only the desired attributes by using object destructuring in the .then function. Here's an example:
.then((json) => {
const {data} = json;
const flightData = Object.values(data).map(({origin, destination, price}) => ({origin, destination, price}));
datos.push(flightData);
})
In this example, Object.values(data) is used to get an array of flight data objects from the data object. Then, .map is used to extract only the origin, destination, and price properties from each object and create a new array of flight data objects with just those properties. This new array is then pushed to the datos array.

Why is my setStateAction not updating with json response data?

I am trying to fetch user data using the GitHub API, but when I make a request using fetch() the request is not sent until after the return(). The response data will only show after the page loads, but I need it before render to use as HTML parameters. I know it has something to do with JSON requests being asynchronous, but I'm not sure how to change the code to set the data properly.
const user = params.get("user");
const [userData, setUserData] = useState(null);
const [reqLimit, setReqLimit] = useState(null);
const getUserData = () => {
fetch(`https://api.github.com/users/${user}`)
.then(response => {response.json();})
.then(json => console.log(json))//'undefined'
.then(json => setUserData(json))
.catch(error => {
console.error('Error:', error);
});
};
useMemo(() => {
fetch(`https://api.github.com/rate_limit`)
.then(response => response.json())
.then(json => {
setReqLimit(json.resources.core);
if (json.resources.core.remaining < 1) {
console.error('Error:', 40
}
});
getUserData();
}, [userData]);
return (
<main>
//userData = null; (Why?)
</main>
)
fetch(`https://api.github.com/users/${user}`)
.then(response => response.json();) // return json
//.then(json => console.log(json))//'undefined' remove this from here
.then(json => setUserData(json))
.catch(error => {
console.error('Error:', error);
});

React/FetchAPI: How to take data from related json by id

I want to take data from JSON, next take another data from related JSON by ID and push it to my state array movies.
This is my code:
state = {
movies: []
}
componentDidMount() {
fetch('https://api.themoviedb.org/3/movie/popular?api_key=APIKEY&page=1')
.then(response => response.json())
.then(data => {
const movies = data.results;
movies.forEach(movie => this.moviePageAndGenres(movie.id, movie));
this.setState({
movies
});
})
}
moviePageAndGenres = (id, element) => {
fetch('https://api.themoviedb.org/3/movie/' + id + '?api_key=APIKEY')
.then(response => response.json())
.then(data => {
element.genres = data.genres;
element.homepage = data.homepage;
});
}
In render() I just console.log my movies to check if data inside is correct.
Output:
image
So it's correct but when I check Component Props these props are not transferred.
image
This is how I transfer props:
const movies = this.state.movies.map(movie =>
<Movie genres={movie.genres}
homepage={movie.homepage}
key={movie.id}
title={movie.title}
poster={movie.poster_path}
rating={movie.vote_average}
/>
)
I guess it's problem with multiple call of asynchronousfetch(). But i don't know how to handle with it.
The reason its not working is, you are firing multiple fetch calls which are async and setting the state immediately after it. setState will get empty movies in that case.
fetch api returns a promise and you should set your state in promise resolution handler. Modify your componentDidMount like this.
componentDidMount() {
fetch('https://api.themoviedb.org/3/movie/popular?api_key=APIKEY&page=1')
.then(response => response.json())
.then(data => {
const movies = data.results;
Promise.all(movies.map(movie => fetch(
`https://api.themoviedb.org/3/movie/${movie.id}?api_key=APIKEY`
)))
.then(resp => Promise.all( resp.map(r => r.json()) ))
.then(result => {
const movies = result.map((data, i) => {
const movie = Object.assign(movies[i], {
genres: data.genres,
homepage: data.homepage
});
return movie;
});
this.setState({
movies
});
});
})
}
You need async await in this case and it’s good to use Promise.all because you are doing fetch in forEach.
For forEach you need await Promise.all and for fetch you need await. Which mean it will wait until the forEach is completed
Change
fetch('https://api.themoviedb.org/3/movie/popular?api_key=APIKEY&page=1')
.then(response => response.json())
.then(data => {
const movies = data.results;
movies.forEach(movie => this.moviePageAndGenres(movie.id, movie));
this.setState({
movies
});
})
To
fetch('https://api.themoviedb.org/3/movie/popular?api_key=APIKEY&page=1')
.then(response => response.json())
.then(async data => {
const movies = data.results;
await Promise.all(movies.forEach(async movie => await this.moviePageAndGenres(movie.id, movie)))
this.setState({
movies
});
})
Also
Change
moviePageAndGenres = (id, element) => {
fetch('https://api.themoviedb.org/3/movie/' + id + '?api_key=APIKEY')
.then(response => response.json())
.then(data => {
element.genres = data.genres;
element.homepage = data.homepage;
});
}
To
moviePageAndGenres = async (id, element) => {
return await fetch('https://api.themoviedb.org/3/movie/' + id + '?api_key=APIKEY')
.then(response => response.json())
.then(data => {
element.genres = data.genres;
element.homepage = data.homepage;
});
}

Using variables in multiple functions - react native

I'm looking to fetch some data then use it to fetch some other data, the first api returns a some news articles, I'm doing a for loop to access descriptions and save it as an array, I want then to use that array to make another fetch request, the issue is that I'm only able to access arrayin the first function, my code looks like that:
makeRemoteRequest = () => {
const url = `https://url.com`;
fetch(url)
.then(res => res.json())
.then(res => {
maindata = res.articles
var array = []
for(let i in maindata){
array.push(maindata[i].description)
}
console.log(array) // Working
this.setState({
data: res.articles,
});
})
console.log(array) // Not working
console.log(this.state.data) // Not working
};
I'm able to use this.state.data in component and render it on a listview.
Second function:
fetch('url', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
'api_key': "81a354b",
'data': array
}),
})
My last attempt was to mix everything in a single function since it's all promises, didn't work
fetch(url)
.then(res => res.json())
.then(res => return res.articles.map(article => article.description) )
.then(res => fetch(otherUrl, { descriptions: res }))
.then(res => {
})
Just define the variable outside of the fetch scope first.
let array = [];
Then inside the fetch:
array.push()
What is the output of this? (could you please add the output formatted in your question?):
fetch(url)
.then(res => res.json())
.then(res => return res.articles.map(article => article.description) )
.then(res => fetch(otherUrl, { descriptions: res }))
//I assume that result needs to be parsed as json as well
.then(res => res.json())
.then(result => {
conole.log("got results:",results);
})
.catch(err =>
console.warn("something went wrong:",err);
)

Iterating through multiple pages of an API response in a JS promise function

I have the following promise function which uses fetch to get data from an API:
const getContacts = token =>
new Promise((resolve, reject) => {
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.then(response => response.json())
.then((data) => {
resolve(data);
})
.catch(err => reject(err));
});
This function is then called in a different file:
getContacts(token)
.then((data) => {
const contacts = data.data;
console.log(contacts);
})
.catch(err => console.error(err));
When there is a larger amount of data returned from the API, it is paginated. The response includes a link that needs to be fetched in order to get the next page. I want my code to first iterate through all pages and collect all data, then resolve the promise. When execution reaches the const contacts = data.data line, it should have data from every page (currently it returns only the first page).
What would be the best way to achieve this?
EDIT:
I tried recursion inside the getContacts function. This way I can iterate through all pages and get all data in one object, but I don't know what's the right way to resolve this back to the code, which initially called the function. The code below doesn't resolve correctly.
const getContacts = (token, allData, startFrom) =>
new Promise((resolve, reject) => {
if (startFrom) {
url = `${url}?${startFrom}`; // the api returns a set of results starting at startFrom (this is an id)
}
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.then(response => response.json())
.then((data) => {
let nextPageExists = false;
Object.assign(allData, data.data);
data.links.forEach((link) => {
if (link.rel === 'next') {
nextPageExists = true;
getContacts(token, allData, link.uri);
}
});
if (!nextPageExists) {
resolve({ data: allData });
}
})
.catch(err => reject(err));
});
First of all, do not use the new Promise constructor when fetch already returns a promise.
Then, just use a recursive approach and chain your promises with then:
function getContacts(token, allData, startFrom) {
return fetch(startFrom ? url + '?' + startFrom : url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
}).then(response => response.json()).then(data => {
Object.assign(allData, data.data);
const nextPage = data.links.find(link => link.rel === 'next');
if (!nextPage)
return allData;
else
return getContacts(token, allData, nextPage.uri);
});
}
Here's a generic function using async/await syntax.
It returns itself until currentPage equals totalPages. You can retrieve these keys from your API response.
async function getData(perPage, page, options, allData = []) {
// fetch data
let base = 'https://api.example.com';
let url = `${base}?perPage=${perPage}&page=${page}`;
let response = await fetch(url, options);
let data = await response.json();
// push this data object (or data.data... whatever) into allData array
allData.push(data);
// get 'totalPages' and 'currentPage' (or whatever your API names these)
let totalPages = data.pagination.total_pages;
let currentPage = data.pagination.current_page;
if (currentPage == totalPages) {
// you're done
return allData;
} else {
// get the next page and repeat
page++;
return getData(perPage, page, options, allData);
}
}
Calling it:
const options = {
method: 'GET',
headers: {
Accept: 'application/json',
appId: 'APP_ID',
apiKey: 'APP_KEY',
'Content-Type': 'application/json'
}
};
let perPage = 100;
let page = 1;
getData(perPage, page, options).then((data) => {
console.log(data)
}).catch((error) => {
console.log(error)
})

Categories