React jsonserver promise result issue - javascript

I am creating a react/ redux app with json fake api server I am trying to add a login and trying to get data from json fake api server, data is showing and all ok , but data is always resulting as a promise and the required data is inside the promise. i tried many ways to distructure but throwing errors , could anyone help me on this,
my axios request
const urlss = "http://localhost:5000/users";
export const userslist = async () => {
const r = await axios.get(urlss);
const data = r.data;
return data;
};
const newout2 = userslist();
const newout = newout2;
console.log(newout);
the place where I am using it
export const login = (credentials) => (dispatch) => {
return new Promise((resolve, reject) => {
const matchingUser =
newout2 &&
newout2.find(({ username }) => username === credentials.username);
if (matchingUser) {
if (matchingUser.password === credentials.password) {
dispatch(setUser(matchingUser));
resolve(matchingUser);
} else {
dispatch(setUser(null));
reject("Password wrong");
}
} else {
dispatch(setUser(null));
reject("No user matching");
}
});
};
i am getting this error

You are using then in your userslist method while awaiting in an async method. drop the then and just use proper await inside an async method.
const urlss = "http://localhost:5000/users";
export const userslist = async () => {
const r = await axios.get(urlss);
const data = r.data;
return data;
};

Related

How to get phone number from User Account in Moralis using React Hooks?

I have two functions. One that is used to to insert a phone number (TEL) into Moralis _User collection on the Moralis Database and another function which is used to query data from it.
This is the one I use to insert data. It works perfectly.
const updateTEL = async() => {
const User = Moralis.Object.extend('_User');
const query = new Moralis.Query(User);
query.equalTo("ethAddress", account);
query.exists("TEL");
const object = await query.first();
object.set("TEL", phoneNumber.phone);
object.save();
console.log("phone number updated successfully" , object);
return monster;
}
Now I am having a problem with this function below.
const queryTEL = async() => {
if(isInitialized) {
const User = Moralis.Object.extend('_User');
const query = new Moralis.Query(User);
query.equalTo("ethAddress", account);
const object = await query.first();
if (object) { setExistingTEL(object.TEL);}
return object;
}
}
const basicQuery = async () => {
const results = await queryTEL();
console.log (" results ", results);
};
I don't know why but it returns the result of 'results' as 'undefined'.
Here is how my useEffect looks like.
useEffect(() => {
setVerificationCode(Math.floor(Math.random()*10000));
basicQuery();
}, []);
Am I doing something wrong?

useQuery always returning undefined data in react-query

I'm new to react-query and I'm trying to move all of my API calls into a new file, out of the useQuery calls.
Unfortunately when I do this all of my data is undefined.
I do see the network calls in the network tab, it just isn't being set properly in useQuery.
Thanks in advance for any help on how to change my code to fix this!
// this works
const { loading, data, error } = useQuery([conf_id], async () => {
const { data } = await axios.get(API_URL + '/event/' + conf_id)
return data
});
// this doesn't work - data is undefined
const axios = require('axios');
const getEventById = async () => {
const { data } = await axios.get(API_URL + '/event/2541' + '?noyear=true');
return data.data;
};
const { loading, data, error } = useQuery('conf_id', getEventById});
// the below variants don't work either
// const { loading, data, error } = useQuery('conf_id', getEventById()});
// const { loading, data, error } = useQuery('conf_id', async () => await getEventById()});
// const { loading, data, error } = useQuery('conf_id', async () => await
// const { data } = getEventById(); return data
// });
An AxiosResponse has a data attribute from which you can access the actual API JSON response.
Like you pointed out, this:
async () => {
const { data } = await axios.get(API_URL + '/event/' + conf_id)
return data
}
Should suffice for the fetching function.
So the final implementation should look like
const axios = require('axios');
const getEventById = async () => {
const { data } = await axios.get(API_URL + '/event/2541' + '?noyear=true');
return data;
};
const { loading, data, error } = useQuery('conf_id', getEventById);
The data you get from the useQuery should be undefined on the first render and once the server responds it will change to whatever the response is.

Save fetched JSON data to sessionStorage

I just figured out how to write an async/await function to fetch data from an API, and it's working, but it's hitting the API like crazy. So now I'm trying to save the fetched data to sessionStorage and only fetch from the API if the data isn't in the sessionStorage.
Here's my code:
const fetchMeetingData = async () => {
console.log('api hit')
try {
const response = await fetch(https://sheet.best...)
const data = await response.json()
validate(data) // Clean data to remove null key values
return data
} catch (e) {
console.log('Fetch error with getMeetingData()')
}
}
const filterMeetings = async (filters) => {
meetings = await fetchMeetingData()
meetings.forEach((meeting) => {
meeting.time2 = moment(meeting.time, ["h:mm A"]).format("HHmm")
})
let today = moment().format("dddd").toString()
let hour = moment().format('HHmm').toString()
let filteredMeetings = meetings.filter(function (matches) {
if (document.querySelector('#select-day').selectedIndex === 0 && filters.searchText === '') {
return matches.day === today &&
moment(matches.time, ["h:mm A"]).format("HHmm") > hour
} else {
return true
}
})
Here's what I've tried:
const fetchMeetingData = async () => {
console.log('api hit')
try {
const response = await fetch(https://sheet.best...)
const data = await response.json()
validate(data) // Clean data to remove null key values
sessionStorage.setItem('meetingData', JSON.stringify(data)) // added this line
return data
} catch (e) {
console.log('Whoa! Fetch error with getMeetingData()')
}
}
I'm not really sure where to go from here, or if this is even the correct approach. My noob instinct was to do something like this, which didn't work.
savedMeetingData = sessionStorage.getItem('meetingData')
const getSavedMeetingData = async () => {
if (savedMeetingData) {
meetings = savedMeetingData
return meetings
} else {
fetchMeetingData()
meetings = await data
return meetings
}
const filterMeetings = async (filters) => {
meetings = await getSavedMeetingData() // replaces call to fetchMeetingData
meetings.forEach((meeting) => {
meeting.time2 = moment(meeting.time, ["h:mm A"]).format("HHmm")
})
I'm not sure if that's exactly the code I was trying but it's close. The problem was the API was still getting hit, even though the data was stored successfully to sessionStorage.
I'd really appreciate some help and/or suggestions on how to clarify this question.
SOLUTION:
Based on answer from #Christian
// StackOverflow Q/A
async function getMeetingData() {
const preLoadedData = sessionStorage.getItem('meetingData')
if(!preLoadedData) {
try {
const response = await fetch('https://sheet.best...')
const data = await response.json()
validate(data)
sessionStorage.setItem('meetingData', JSON.stringify(data))
console.log('api hit')
return data
} catch (e) {
console.log('Whoa! Fetch error with getMeetingData()')
}
} else {
console.log('no api hit!!!')
return JSON.parse(preLoadedData)
}
}
async function getSavedMeetingData() {
const meetings = await getMeetingData()
return meetings
}
const filterMeetings = async (filters) => {
meetings = await getSavedMeetingData()
meetings.forEach((meeting) => {
meeting.time2 = moment(meeting.time, ["h:mm A"]).format("HHmm")
})
If you could be more explicit on what exactly did not work it would be great :) (did not save data in sessionStorage?, could not retrieve it?, etc...). Anyway, maybe you could try something like this and see if it helps:
async function getSavedMeetingData() {
const meetingData = await getMeetingData();
}
async function getMeetingData() {
const preloadedData = sessionStorage.getItem('meetingData');
if (!preloadedData) {
try {
const response = await fetch('https://myapiurl.com/');
const data = validate(response.json());
sessionStorage.setItem('meetingData', JSON.stringify(data));
return data;
} catch (e) {
console.log('Whoa! Fetch error with getMeetingData()');
}
} else {
return JSON.parse(preloadedData);
}
}
One more reminder (just in case), keep in mind you are saving this to sessionStorage, so if you close the tab do not expect to have the information saved, in that case you should use localStorage.

How to optimally combine multiple axios responses

I am working with a React app. I have to create 2 objects using responses from 3 different APIs. For example:
DataObject1 will be created using API1 and API2
DataObject2 will be created using API1, API2, and API3
So, I am thinking about what would be the most optimal way of doing this by making sure 1 call each API only once.
I was thinking this:
const requestOne = axios.get(API1);
const requestTwo = axios.get(API2);
const requestThree = axios.get(API3);
axios.all([requestOne, requestTwo, requestThree]).then(axios.spread((...responses) => {
const dataObject1 = createDataObject1(responses[0], responses[1]);
const dataObject2 = createDataObject2(responses[0], responses[1], responses[2]);
// use/access the results
})).catch(errors => {
// react on errors.
})
const createDataObject1 = (response1, response2) => { //Combine required data and return dataObject1 }
const createDataObject2 = (response1, response2, response3) => { //Combine required data and return dataObject2 }
Is there a better way of doing this?
Looks fine.
You can change this
axios.all([requestOne, requestTwo, requestThree]).then(axios.spread((...responses) => {
const dataObject1 = createDataObject1(responses[0], responses[1]);
const dataObject2 = createDataObject2(responses[0], responses[1], responses[2]);
// use/access the results
})).catch(errors => {
// react on errors.
})
to
axios.all([requestOne, requestTwo, requestThree]).then((response) => {
const dataObject1 = createDataObject1(responses[0], responses[1]);
const dataObject2 = createDataObject2(responses[0], responses[1], responses[2]);
// use/access the results
}).catch(errors => {
// react on errors.
})
because it is unnecessary to spread and rest.
If you don't want to use them like responses[0], responses[1], etc then you can use:
axios.all([requestOne, requestTwo, requestThree]).then(axios.spread((response1, response2, response3) => {
const dataObject1 = createDataObject1(response1, response2);
const dataObject2 = createDataObject2(response1, response2,response3);
// use/access the results
})).catch(errors => {
// react on errors.
})
Are you using thunk middleware to make async calls in Redux? I don't want to assume that you are, but that seems like a good basic approach here.
const requestOne = axios.get(API1);
const requestTwo = axios.get(API2);
const requestThree = axios.get(API3);
Okay. So now requestOne.data has the result of making the axios get request. Or, would if the thunk creator was async and the code was const requestOne = await axios.get(API1);
Do you need to parse the data further from request___.data ?
If not you can just have
const dataObj1 = { response1: requestOne.data, response2: requestTwo.data }
const dataObj2 = { ... dataObject1, response3: requestThree.data };
Full answer:
// store/yourFile.js code
export const YourThunkCreator = () => async dispatch => {
try {
const const requestOne = await axios.get(API1);
// other axios requests
const dataObj1 = { response1: requestOne.data, response2: requestTwo.data }
const dataObj2 = { ... dataObject1, response3: requestThree.data };
// other code
dispatch(// to Redux Store);
} catch (error) {
console.error(error);
}

How to fetch data from multiple urls at once?

I have a function that fetches from a url in React
const DataContextProvider = (props) => {
const [isLoading, setLoading] = useState(false);
const [cocktails, setCocktails] = useState([]);
useEffect(() => {
const fetchCocktailList = async () => {
const baseUrl = 'https://www.thecocktaildb.com/api/json/v1/1/';
setLoading(true);
try {
const res = await fetch(`${baseUrl}search.php?s=margarita`);
const data = await res.json();
console.log(data);
setCocktails(data.drinks);
setLoading(false);
} catch (err) {
console.log('Error fetching data');
setLoading(false);
}
};
fetchCocktailList();
}, []);
How I'm mapping data so far.
const DrinkList = () => {
const { cocktails } = useContext(DataContext);
return (
<div className='drink-list-wrapper'>
{cocktails.length > 0 &&
cocktails.map((drink) => {
return <DrinkItem drink={drink} key={drink.idDrink} />;
})}
</div>
);
};
However I want to fetch from this url also ${baseUrl}search.php?s=martini
I would like a good clean way to do this and set my state to both of the returned data.
First base the data fetch function on a parameter:
const fetchCocktail = async (name) => {
const baseUrl = 'https://www.thecocktaildb.com/api/json/v1/1/';
try {
const res = await fetch(`${baseUrl}search.php?s=` + name);
const data = await res.json();
return data.drinks;
} catch (err) {
console.log('Error fetching data');
}
}
Then use Promise.all to await all results:
setLoading(true);
var promises = [
fetchCocktail(`margarita`),
fetchCocktail(`martini`)
];
var results = await Promise.all(promises);
setLoading(false);
DrinkList(results);
Where results will be an array with the responses that you can use on the DrinkList function.
Here's a method which will let you specify the cocktail names as dependencies to the useEffect so you can store them in your state and fetch new drink lists if you want new recipes. If not, it'll just be a static state variable.
I've also added another state variable errorMessage which you use to pass an error message in the case of failure.
Also, you should include the appropriate dependencies in your useEffect hook. The setState functions returned by calls to useState are stable and won't trigger a re-run of the effect, and the cocktailNames variable won't trigger a re-run unless you update it with new things to fetch.
const DataContextProvider = (props) => {
const [isLoading, setLoading] = useState(false);
const [cocktails, setCocktails] = useState([]);
const [errorMessage, setErrorMessage] = useState(''); // holds an error message in case the network request dosn't succeed
const [cocktailNames, setCocktailNames] = useState(['margarita', 'martini']); // the search queries for the `s` parameter at your API endpoint
useEffect(() => {
const fetchCocktailLists = async (...cocktailNames) => {
const fetchCocktailList = async (cocktailName) => {
const baseUrl = 'https://www.thecocktaildb.com/api/json/v1/1/search.php';
const url = new URL(baseUrl);
const params = new URLSearchParams({s: cocktailName});
url.search = params.toString(); // -> '?s=cocktailName'
const res = await fetch(url.href); // -> 'https://www.thecocktaildb.com/api/json/v1/1/search.php?s=cocktailName'
const data = await res.json();
const {drinks: drinkList} = data; // destructured form of: const drinkList = data.drinks;
return drinkList;
};
setLoading(true);
try {
const promises = [];
for (const cocktailName of cocktailNames) {
promises.push(fetchCocktailList(cocktailName));
}
const drinkLists = await Promise.all(promises); // -> [[drink1, drink2], [drink3, drink4]]
const allDrinks = drinkLists.flat(1); // -> [drink1, drink2, drink3, drink4]
setCocktails(allDrinks);
}
catch (err) {
setErrorMessage(err.message /* or whatever custom message you want */);
}
setLoading(false);
};
fetchCocktailList(...cocktailNames);
}, [cocktailNames, setCocktails, setErrorMessage, setLoading]);
};
var promises = [
fetchCocktail(api1),
fetchCocktail(api2)
];
var results = await Promise.allSettled(promises);

Categories