Returns an empty array - javascript

I am trying to get the data from this endpoint but I am getting an empty array. Can you help me with this? thanks
I've been trying to do it, with the other methods I have I can get the corresponding data.
I tried several ways but still can't find a solution.
http://localhost:8081/getmnemonicsandtagsforabm this is the methood
const DataTable = () => {
const provider = useContext(AppContext);
let [editServiceStatus, setEditServiceStatus] = useState(false);
let [configServiceStatusButton, setConfigServiceStatusButton] =
useState(false);
let [serviceItem_selected, setServiceItem_selected] = useState([]);
let [fetchServiceDetail, setFetchServiceDetail] = useState([]);
let sessionID = localStorage.getItem("session_id");
const [array_services, setArray_services] = useState({ khad_services: [] });
const [array_services2, setArray_services2] = useState({ khad_services: [] });
const [active_dropdown, setActive_dropdown] = useState(false);
const [active_serviceConfig, setActive_serviceConfig] = useState(false);
useEffect(() => {
let session_id = {
session_id: sessionID,
};
fetch("http://localhost:8081/getservicelist", {
method: "POST",
body: JSON.stringify(session_id),
})
.then((res) => res.json())
.then((data) => {
//console.log(`****__ data: __****: `, data);
localStorage.setItem("array_services", JSON.stringify(data));
setArray_services(data);
})
.catch((err) => console.log(err));
}, []);
useEffect(() => {
let session_id = {
session_id: sessionID,
};
fetch("http://localhost:8081/getmnemonicsandtagsforabm", {
method: "POST",
body: JSON.stringify(session_id),
})
.then((res) => res.json())
.then((data) => {
console.log(`****__ data:__****: `, data);
localStorage.setItem("mnemonicsAndTags", JSON.stringify(data));
localStorage.setItem("mnemonics", JSON.stringify(data.mnemonics));
localStorage.setItem("tags", JSON.stringify(data.tags));
localStorage.setItem("tagsForMnemonics", JSON.stringify(data.tagsForMnemonics));
setArray_services(data);
})
.catch((err) => console.log(err));
}, []);
I await the return of the array accordingly

Related

How can i run a function in every screen user is navigating to?

how can I run a function in the whole app? like if that function is triggered then even if a user is navigating to a different screen then also that function will do its work until that function work is done how can I do this in react native? I want to do this with my PostImageHandler once postimagehandler is triggered then that function will run and it won't stop until the image is uploaded also user can navigate through different screens during that process
const [loading1, setLoading1] = useState(false)
const [loading2, setLoading2] = useState(false)
const [photo, setPhoto] = useState(null)
const { postImage } = route.params;
const PostImageHandler = useCallback(async () => {
if (!postImage.cancelled) {
const response = await fetch(postImage);
const blob = await response.blob();
const filename = postImage.substring(postImage.lastIndexOf('/') + 1);
const ref = firebase.storage().ref().child(filename);
const snapshot = await ref.put(blob);
const url = await snapshot.ref.getDownloadURL();
setPhoto(url)
console.log(url)
}
}, [postImage])
useEffect(() => {
PostImageHandler();
}, [PostImageHandler])
const handleUpload = useCallback(() => {
if (postImage != null) {
AsyncStorage.getItem('user')
.then(data => {
setLoading2(true)
fetch('https://mybackend.com/addpost', {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: JSON.parse(data).user.email,
post: postImage,
})
})
.then(res => res.json())
.then(data => {
if (data.message == 'Photo added successfully') {
alert('Photo added successfully')
setLoading2(false)
navigation.navigate('home')
} else {
alert('Something went wrong, please try again')
setLoading2(false)
}
})
})
} else {
alert('Please wait photo is processing')
}
}, [photo, navigation, setLoading2]);

How to make API calls in Vanilla JS

Am building a weather app using vanilla JS and weatherbit rapid API, but whenever I run the program, it logs an error Can not read properties of undefined (reading 'temp')
const tempValue = document.getElementsByClassName('temp')
// console.log(cityName)
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Key': '************************************',
'X-RapidAPI-Host': 'weatherbit-v1-mashape.p.rapidapi.com'
}
}
document.getElementById('submit').addEventListener('click', e => {
e.preventDefault()
fetch(
'https://weatherbit-v1-mashape.p.rapidapi.com/forecast/3hourly?lat=35.5&lon=-78.5',
options
)
.then(response => response.json())
.then(data => {
let tempval = data['temp']
tempValue.innerHtml = tempval
})
.catch(err => console.error(err))
})
pls consult the docs.
https://rapidapi.com/weatherbit/api/weather
response object structure is:
{
country_code:"US",
lon:-78.5,
data: [...],
city_name:"Four Oaks",
lat:35.5,
timezone:"America/New_York",
state_code:"NC",
}
To access 'temp'. use `
fetch(
'https://weatherbit-v1-mashape.p.rapidapi.com/forecast/3hourly?lat=35.5&lon=-78.5',
options
).then(response => {
const someItemIndex = 0;
console.log(response.data);
const tempval = response.data[someItemIndex].temp
tempValue.innerHtml = tempval
})
.catch(err => console.error(err))
there is no temp in response. and there is no any field 'temp' in data. Temp is defined only on iterable items of data array.
After some advice I received from this platform, I have managed to modify the code and it's working perfectly. The problem was in the way I was accessing the fields from the JSON. I am new to APIs and this is an excellent start for me thank you.
Modified Code
const tempValue = document.querySelector('.temp')
const cityName = document.querySelector('.city_name')
const humid = document.querySelector('.humidity')
const weatherValue = document.querySelector('.weather')
// console.log(cityName)
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Key': '30583b6ad4msh649637ae1b0f6d3p1edde0jsn53b7839146a2',
'X-RapidAPI-Host': 'weatherbit-v1-mashape.p.rapidapi.com'
}
}
document.getElementById('submit').addEventListener('click', e => {
e.preventDefault()
fetch(
'https://weatherbit-v1-mashape.p.rapidapi.com/forecast/3hourly?lat=35.5&lon=-78.5',
options
)
//Modified code
.then(response => response.json())
.then(response => {
const someItemIndex = 0
console.log(response.data)
const tempval = response.data[someItemIndex].temp
const cityval = response.city_name
const weatherval = response.data[someItemIndex].weather.description
// console.log(tempval)
tempValue.innerHTML = `<h3>Temperature: </h3>${tempval}&#x2103`
weatherValue.innerHTML = `<h3>Weather Description: </h3>${weatherval}`
cityName.innerHTML = `<h3>City Name: </h3>${cityval}`
})
.catch(err => console.error(err))
})

Call custom React async hook within a component and se it's state again

I have a custom react hook fetching number of comments from an API that looks like this:
export async function useFetchNumberOfComments(articleId) {
const [numberOfComments, setNumbeOfComments] = useState(0);
useEffect(() => {
(async () => {
try {
const response = await axios.get(`https://example.com/${articleId}`, {
headers: {
"Content-Type": "application/json",
"X-API-KEY": "X",
Authorization: localStorage.getItem("access_token"),
},
});
const data = await response.data;
setNumbeOfComments(data);
} catch (err) {
console.log(err);
}
})();
}, []);
return numberOfComments;
}
And I want to use it in a Article component that looks like this:
import { useFetchNumberOfComments } from "../utils";
const SingleArticle = () => {
let { id } = useParams();
// Important state
const [numOfComments, setNumOfComments] = useState(0);
// Not important states
const [title, setTitle] = useState("");
const [author, setAuthor] = useState("");
const [content, setContent] = useState("");
const [comments, setComments] = useState([]);
const [commentAuthor, setCommentAuthor] = useState("");
const [commentContent, setCommentContent] = useState("");
const [imageId, setImageId] = useState("");
const [imageUrl, setImageUrl] = useState("");
const [createdAt, setCreatedAt] = useState();
const postComment = async (e) => {
e.preventDefault();
const dataToSend = {
articleId: id,
author: commentAuthor,
content: commentContent,
};
try {
await axios.post(`https://example.com/comments`, dataToSend, {
headers: {
"Content-Type": "application/json",
"X-API-KEY": "X",
Authorization: localStorage.getItem("access_token"),
},
});
// Here, fetch the number of comments from my custom hook and update numOf Comments in this component
setCommentAuthor("");
setCommentContent("");
} catch (err) {
console.log(err);
}
};
return (
<>
<form onSubmit={postComment}>
// Here are some inputs, labels and a submit button
</form>
<h4 className={styles.h1}>Comments({numOfComments})</h4>
</>
);
};
export default SingleArticle;
Now, the problem is that I have no idea how to do the mentioned activity within the Article component: Once the form data(for comment) are sent, trigger the useFetchNumberOfComments custom hook and set the numOfComments state inside article component to the newly fetched data.
I think you'd be better served refactoring the useFetchNumberOfComments hook to return a fetch function and some fetch request meta data, i.e. loading and response and error states.
Example:
export function useFetchNumberOfComments() {
const [numberOfComments, setNumbeOfComments] = useState(0);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const fetchArticleCommentCount = useCallback(async (articleId) => {
setLoading(true);
try {
const response = await axios.get(`https://example.com/${articleId}`, {
headers: {
"Content-Type": "application/json",
"X-API-KEY": "X",
Authorization: JSON.parse(localStorage.getItem("access_token")),
},
});
const data = await response.data;
setNumbeOfComments(data);
setError(null);
return data;
} catch (err) {
console.log(err);
setError(err);
} finally {
setLoading(false);
}
}, []);
return {
fetchArticleCommentCount,
numberOfComments,
loading,
error
};
};
...
import { useFetchNumberOfComments } from "../utils";
const SingleArticle = () => {
const { id } = useParams();
const {
fetchArticleCommentCount,
numberOfComments,
} = useFetchNumberOfComments();
// Important state
const [numOfComments, setNumOfComments] = useState(0);
// Not important states
...
const postComment = async (e) => {
e.preventDefault();
const dataToSend = {
articleId: id,
author: commentAuthor,
content: commentContent,
};
try {
await axios.post(`https://example.com/comments`, dataToSend, {
headers: {
"Content-Type": "application/json",
"X-API-KEY": "X",
Authorization: localStorage.getItem("access_token"),
},
});
// await returned comment count and update local state
const commentCount = await fetchArticleCommentCount(id);
setNumOfComments(commentCount);
// or use the updated numberOfComments value returned from hook
fetchArticleCommentCount(id);
// both are available, but you only need one or the other here
setCommentAuthor("");
setCommentContent("");
} catch (err) {
console.log(err);
}
};
return (
<>
<form onSubmit={postComment}>
// Here are some inputs, labels and a submit button
</form>
<h4 className={styles.h1}>Comments({numberOfComments})</h4>
</>
);
};
export default SingleArticle;

useEffect efficiency in Star Wars API

I need some help with me current project making in React. I'am making a star-wars-app for my job interview and I stucked on a one problem.
Fetch efficiency.
I'am fetching this data, and then fetching some more because of the url's in the first fetched data, and everything fetches good, but first i have the 'url's' seeing in the table and then it changes into correct data.
I want to set the 'fetched' state to true when everything is rendered correctly but I don't know how to do it.
const api = `https://swapi.dev/api/people/`;
const [characters, setCharacters] = useState([]);
const [speciesOptions, setSpeciesOptions] = useState([]);
const [homeworldOptions, setHomeworldOptions] = useState([]);
const [fetched, setFetched] = useState(false);
useEffect(() => {
const fetchedTimeout = () => {
setTimeout(() => {
setFetched(true);
}, 2000);
};
const fetchArray = (array, arrName) => {
for (let elem of array) {
fetch(elem).then((response) =>
response.json().then((data) => {
array.shift();
array.push(data.name);
})
);
}
if (arrName === "species") {
if (!array.length) {
array.push("Unspecified");
}
}
};
async function fetchOtherData(characters) {
await characters.forEach((character) => {
const homeworld = character.homeworld;
const vehicles = character.vehicles;
const starships = character.starships;
const species = character.species;
fetch(homeworld).then((response) =>
response.json().then((data) =>
setCharacters((prevData) =>
prevData.map((prevCharacter) =>
prevCharacter.homeworld === homeworld
? {
...prevCharacter,
homeworld: data.name,
}
: prevCharacter
)
)
)
);
fetchArray(vehicles);
fetchArray(starships);
fetchArray(species, "species");
});
await setCharacters(characters);
await fetchedTimeout();
}
const fetchAllCharacters = (allCharacters, data) => {
if (data.next) {
fetch(data.next)
.then((response) => response.json())
.then((data) => {
allCharacters.push(...data.results);
fetchAllCharacters(allCharacters, data);
});
}
if (!data.next) {
fetchOtherData(allCharacters);
}
};
async function fetchApi() {
const allCharacters = [];
await fetch(api)
.then((response) => response.json())
.then((data) => {
allCharacters.push(...data.results);
fetchAllCharacters(allCharacters, data);
})
.catch((error) => console.log(error));
}
const setSpeciesFiltering = () => {
const speciesFiltering = [];
for (let character of characters) {
const characterSpecies = character.species.join();
const foundSpecies = speciesFiltering.indexOf(characterSpecies);
if (foundSpecies === -1) {
speciesFiltering.push(characterSpecies);
}
}
const speciesOptions = speciesFiltering.map((species) => (
<option value={species}>{species}</option>
));
setSpeciesOptions(speciesOptions);
};
const setHomeworldFiltering = () => {
const homeworldFiltering = [];
for (let character of characters) {
const characterHomeworld = character.homeworld;
const foundSpecies =
homeworldFiltering.indexOf(characterHomeworld);
if (foundSpecies === -1) {
homeworldFiltering.push(characterHomeworld);
}
}
const homeworldOptions = homeworldFiltering.map((homeworld) => (
<option value={homeworld}>{homeworld}</option>
));
setHomeworldOptions(homeworldOptions);
};
fetchApi();
setSpeciesFiltering();
setHomeworldFiltering();
}, []);
I will appreciate your response.
Okay, after all the comments (thanks for that!) i changed the code to something like this.
useEffect(() => {
const fetchOtherData = (characters) => {
const charactersWithAllData = [];
characters.forEach((character) => {
const homeworld = character.homeworld;
const species = character.species;
const vehicles = character.vehicles;
const starships = character.starships;
let urls = [homeworld, ...species, ...vehicles, ...starships];
Promise.all(
urls.map((url) => {
if (url.length) {
fetch(url)
.then((response) => response.json())
.then((data) => {
if (url.search("species") > 0) {
character.species = data.name;
}
if (url.search("planets") > 0) {
character.homeworld = data.name;
}
if (url.search("vehicles") > 0) {
character.vehicles.shift();
character.vehicles.push(data.name);
}
if (url.search("starships") > 0) {
character.starships.shift();
character.starships.push(data.name);
}
})
.catch((err) => console.error(err));
}
if (!url.length) {
if (url.search("species")) {
character.species = "Unspecified";
}
if (url.search("vehicles")) {
character.vehicles = "";
}
if (url.search("starships")) {
character.starships = "";
}
}
})
).then(charactersWithAllData.push(character));
});
return charactersWithAllData;
};
const fetchApi = () => {
const characters = [];
Promise.all(
[api].map((api) =>
fetch(api)
.then((response) => response.json())
.then((data) => characters.push(...data.results))
.then((data) => {
setCharacters(fetchOtherData(characters));
})
)
);
};
fetchApi();
}, []);
In what point do i have to set the 'characters' state ? Because in the situation above the data first shows on the screen, and then the state is set.
As other comments say, using Promise.all and refactoroing your useEffect is best solution for this.
But this might be helpful if you don't want to change a lot.
(but still consider refactor your hook)
const [loading, setLoading] = useState(0);
const isLoading = loading > 0;
// replace your fetches with below:
const myFetch = async (path) => {
try {
setLoading(loading => loading + 1);
return await fetch(path);
} finally {
setLoading(loading => loading - 1);
}
};
useEffect(() => {
// do your stuffs
}, []);

UseEffect hook not work well when re update data?

I have a list of orders, I'm using FlatList to render them,
I have 2 main concepts should I have "Load More, Pull to Refresh"
In my case user can edit the order then pull to refresh to get the newly updated data, and another case for load more "pagination".
SO
Load more functionality work properly well, and gets the new data from the server and pushed to the state with the old data,
BUT pull to refresh not works, it's not updated the data when setState, although the function that gets data triggered, and I can see the updated data in the console, It just renders the old data!
Here's a code snippet.
const OpenedAppointments = () => {
const [openedAppointment, setOpenedAppointment] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [lastPage, setLastPage] = useState(null);
const [loading, setLoading] = useState(false);
const [isFetch, setIsFetch] = useState(false);
const loadMoreOrders = () => {
if (currentPage <= lastPage - 1) {
setLoading(true);
setCurrentPage((prevPage) => prevPage + 1);
console.log('loadMore??');
}
};
const getOpenOrders = useCallback(() => {
let AuthStr =
'Bearer ';
const headers = {
'Content-Type': 'application/json',
Authorization: AuthStr,
};
Api.post(
`/open_orders?page=${currentPage}`,
{},
{
headers,
},
)
.then((res) => {
let last_Page = res.data.open_orders.last_page;
let allOpenedOrders = res.data.open_orders.data;
console.log('allOpenedOrders', allOpenedOrders);
console.log('last_Page', last_Page);
console.log('currentPage', currentPage);
setLastPage(last_Page);
setOpenedAppointment((prevOpenedOrders) => [
...prevOpenedOrders,
...allOpenedOrders,
]);
setLoading(false);
setIsFetch(false);
})
.catch((err) => console.log('err', err));
}, [currentPage]);
// Delete Appointments
const cancelAppointem = (appointmentID) => {
let AuthStr =
'Bearer...';
const headers = {
'Content-Type': 'application/json',
Authorization: AuthStr,
};
Api.post(
'/cancel/order',
{
id: appointmentID,
},
{
headers,
},
)
.then((res) => {
setIsOpenedCancelModal((opened) => !opened);
console.log(res.data);
setOpenedAppointment((prev) =>
prev.filter((item) => item.id !== appointmentID),
); // works very well
})
.catch((err) => console.log(err));
};
const _refresh = () => {
setIsFetch(true);
getOpenOrders();
};
useEffect(() => {
getOpenOrders();
}, [getOpenOrders]);
const keyExtractor = (item, index) => String(index);
return (
<FlatList
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.flatListCon}
data={openedAppointment}
ListEmptyComponent={renderEmpty}
renderItem={renderItems}
keyExtractor={keyExtractor}
ListFooterComponent={_renderFooter}
onEndReached={loadMoreOrders}
onEndReachedThreshold={0.1}
onRefresh={_refresh}
refreshing={isFetch}
/>
);
};
Figure out the problem
At first render I got 5 orders from API, If I update the first order then pull to refresh, I got the same 5 order again but order number one is updated
So in getOpenOrders function, it merges old orders with new orders so I can see duplicated orders first 5 order "old data"
second 5 order "updated data".
But I have other concepts for load more "pagination" so it's should I have the merged arrays to get new order at the next page "2" with the prev order in the previous page "1"!
So how can I fix this?
Edit Data structure response
open_orders = [
{id: 14, status: "Cash", cost: "25.00", service_id: 11, vendor_id: 3, …}
{id: 15, status: "Cash", cost: "25.00", service_id: 11, vendor_id: 3, …}
...
]
Your effect should listen isFetch
const _refresh = () => {
setIsFetch(true);
};
useEffect(() => {
getOpenOrders();
}, [isFetch]);
const [updatePage, setUpdatePage] = useState(1)
const [isUpdate, setIsUpdate] = useState(false)
// call `setUpdatePage` when you edit the data
/**
* const edit = (record)=>{
* ...
* const updatePageIndex = openedAppointment.findIndex((item)=> item.id === record.id)
* const updatePageNum = Math.ceil(updatePageIndex/openedAppointment.length)
* setUpdatePage(updatePageNum)
* setIsUpdate(true)
* }
*
**/
const getOpenOrders = useCallback(() => {
const pageNum = isUpdate ? updatePage : currentPage
let AuthStr =
'Bearer ';
const headers = {
'Content-Type': 'application/json',
Authorization: AuthStr,
};
Api.post(
`/open_orders?page=${pageNum}`,
{},
{
headers,
},
)
.then((res) => {
let last_Page = res.data.open_orders.last_page;
let allOpenedOrders = res.data.open_orders.data;
...
if(openedAppointment.length > 0) {
const newOpenedOrders = openedAppointment.map((item)=>{
const target = allOpenedOrders.find(ele=> ele.id === item.id) || []
return {
...item,
...target,
}
})
setOpenedAppointment(newOpenedOrders);
} else {
setOpenedAppointment(allOpenedOrders)
}
setIsUpdate(false)
...
})
.catch((err) => console.log('err', err));
}, [currentPage]);

Categories