trying to call api with multiple objects react JS - reactjs

I'm trying to call a specific object within an api but it returns error
...
calling the first one works but when i call the second objects it returns error
here's the code
Api link : https://opentdb.com/api.php?amount=3&difficulty=easy&type=multiple
const [quiz,setQuiz] = React.useState([""])
React.useEffect(() => {
async function getQuiz() {
const res = await fetch(
"https://opentdb.com/api.php?amount=3&difficulty=easy&type=multiple"
);
const data = await res.json();
setQuiz(data.results);
}
getQuiz();
});
return (
<QuizPage
questionOne={quiz[0].question} //this works //
questionsTwo={quiz[1].question} //this not //
/>
);
I tried to create separate states but it did not work either
i tried to create a seperate state and calling a second object but that didnt work either, i also tried to map over it and still didnt work, i tried many other methods to call api but still no solutions and i get this error in the console ncaught TypeError Cannot read properties of undefined reading 'question, Consider adding an error boundary to your tree to customize error handling behavior, logCapturedError

const [quiz,setQuiz] = React.useState([""])
Your initial sate has only one element, so quiz[1] is undefined, and quiz[1].question will throw an error. You will need to check for the case where you don't have data and either show nothing, or show some loading screen. For example:
const [quiz,setQuiz] = React.useState(null)
// ...
if (!quiz) {
return <div>Loading...</div>
} else {
return (
<QuizPage
questionOne={quiz[0].question}
questionsTwo={quiz[1].question}
/>
);
}

Related

Mapping State in React with Server Requests

I'm new to React as we are trying to migrate our app from AngularJS. One thing I'm struggling to wrap my head around is what's the best way to make and cache state mapping requests.
Basically, I would do a search, that returns a list of objects and one of the field is a status code (e.g. 100, 200, 300, etc.), some number. To display the result, I need to map that number to a string and we do that with a http request to the server, something like this:
GET /lookup/:stateId
So my problem now is:
I have a list of results but not many different states, how can I make that async call (useEffect?) to make that lookup only once for different stateId? Right now, I can get it to work, but the request is made on every single mapping. I'm putting the Axio call in a utility function to try and reuse this across multiple pages doing similar things, but is that the "React" way? In AngularJS, we use the "|" filter to map the code to text.
Once I have that mapping id => string, I want to store it in cache so next one that needs to map it no longer make the http request. Right now, I put the "cache" in the application level context and use dispatch to update/add values to the cache. Is that more efficient? It appears if I do a language change, where I keep the language in the same application context state, the cache would be re-initialized, and I'm not sure what other things would reset that. In AngularJS, we used the $rootState to 'cache'.
Thanks for any pointers!
In a lookupUtil.js
const DoLookupEntry = async (entryId) => {
const lookupUrl = `/lookup/${entryId}`;
try {
const response = await Axios.get(looupUrl,);
return response.data;
} catch (expt) {
console.log('error [DoLookupEntry]:',expt);
}
}
In a formatUtils.js
const formatLookupValue = (entryId) => {
const appState = useContext(AppContext);
const appDispatch = useContext(DispatchContext);
const language = appState.language;
if (appState.lookupCache
&& appState.lookupCache[entryId]
&& appState.lookupCache[entryId][language]) {
// return cached value
const entry = appState.lookupCache[entryId][language];
return entry.translatedValue;
}
// DoLookup is async, but we are not, so we want to wait...
DoLookupEntry(entryId)
.then((entry) => { // try to save to cache when value returns
appDispatch({type: States.APP_UPDATE_LOOKUP_CACHE,
value:{language, entry}})
return entry.translatedValue;
});
}
And finally the results.js displaying the result along the line (trying formatLookupValue to map the id):
{searchState.pageResults.map((item) => {
return (
<tr>
<td><Link to={/getItem/item.id}>{item.title}</Link></td>
<td>{item.detail}</td>
<td>{formatLookupValue(item.stateId)}</td>
</tr>
)
})}

i cannot save a response after execute the request using axios Instance (Pokedex - PokeApi)

I trying to do a pokedex using react and pokeAPI but when i try to save the response on a constant and return it this always return undefined.
c
try {
const pokemonResponse = getPokemonByName({
pokemonName,
})
console.log(pokemonResponse)
return pokemonResponse
} catch (e) {
throw new Error("Ups! We had a problem with product's fetch. Details: " + e)
}
}
here a codesandbox with the project
https://codesandbox.io/s/compassionate-haslett-ngv7z?file=/src/data/storage/PokemonStorage.ts
I found 2 issues in the code. See my fork on Codesandbox.
getPokemonByName returned undefined (because it didn't return anything). It should return Promise containing response from API I assume.
Compare it to getAllPokemons function in the same file that actually returns Promise.
Make sure you understand the arrow functions syntax.
Now you need to add await when calling getPokemonByName in async function. This will correctly assign result to pokemonResponse. See docs on async functions.

Axios Response Data not saved in State

I have a custom hook useServerStatus that fetches from a RESTful API with axios. Checking the network tab, the response went through fine, I can see all my data. Using console.log to print out the result or using debugger to check the result in the browser works flawlessly. However, calling the setState method that I get from useState will not save the response data.
ServerStatus Interface (ServerStatus.ts)
interface ServerStatus {
taskid: string
taskmodule: string
taskident?: string
status: string
server: string
customer: string
}
useServerStatus Hook (useServerStatus.ts)
export default function useServerStatus() {
const [serverStatus, setServerStatus] = useState<ServerStatus[][]>([]);
useEffect(() => {
fetchServerStatus();
}, []);
const fetchServerStatus = () => {
axios.get<ServerStatus[][]>(`${config.apiURL}/servers`)
.then(res => setServerStatus(res.data));
}
return serverStatus;
}
Network Tab
https://i.imgur.com/cWBSPVz.png
The first request you see in the network tab is handled the same exact way, no problems there.
React Developer Console
https://i.imgur.com/YCq3CPo.png
Try
const fetchServerStatus = () => {
axios.get<ServerStatus[][]>(`${config.apiURL}/servers`)
.then(res => { setServerStatus(res.data) });
}
So, to answer my own question:
I figured out that the problem wasn't about data not being saved in state, but data not correctly being received by axios.
I fixed it with a workaround. Instead of returning a ServerStatus[][] in my backend, I returned a ServerStatus[]. I was able to use this data instead.
Following the lesson here https://reactjs.org/docs/hooks-custom.html the most obvious thing that jumps out to me is that you aren't returning the state variable serverStatus in your code vs. the example is returning "isOnline". Try to match this by returning serverStatua in your custom effect to see if it helps.

How to hide an AntD message after another Promise (API request) completes?

I want to make an API call. When the API call started I display a loading message. I want to stop showing this message when the API call is a success.
This is the message I am using now
message.loading({
content: "Loading...",
duration: 0,});
I don't know how to stop the message when the API call is a success.
The message.loading (and other functions, like message.success, message.info, etc) return a function that closes the message-box when invoked. This is demonstrated in this sample from their docs:
const showThenHide = () => {
// This starts showing the message:
const hide = message.loading('Action in progress..', 0);
setTimeout(hide, 2500); // <-- This invokes the `hide` function after 2.5 seconds
};
showThenHide();
I assume you already have a Promise<T> that represents your API request in-progress. In which case:
const hideMessage = message.loading('Loading..', /*duration:*/ 0);
try {
const apiRequestPromise = someApiClient.doSomething();
const apiRequestRespons = await apiRequestPromise; // You can also inline this await
renderApiResponse( apiRequestRespons );
}
catch ( err ) {
// TODO: Error-handling
}
finally {
hideMessage();
}
It's important to have the hideMessage() invocation in a finally block and not just after the await apiRequestPromise because if an exception is thrown inside the try block (or if you don't have a try block at all) then the message will remain open indefinitely, which isn't what you want.
if you had checked the document of antd about message you would see how they destroy the loading message there:
message.loading(..) return hide function when excute.
to hide the loading, simply call the hide message.
so I can give you an example to handle asynchronous API call:
const hide = message.loading('Loading...',0)
API.getUser(id).then(res => {
//handle response
hide()
}

Uncaught (in promise) TypeError: Cannot read property 'headers' of undefined

So, I'm attempting to pass a user's ip address in my app, as follows:
pages/Item.js
const Item = props => (
<div>
<SingleItem id={props.query.id} userIP={props.userIP} />
</div>
);
Item.getInitialProps = async ({ req }) => {
const userIP = req.headers['x-real-ip'] || req.connection.remoteAddress
return { userIP }
}
export default withAmp(Item, { hybrid: true });
but get the above mentioned error message (See attached image) when navigating to the page. But if I then do a hard reload of the page the ip details are correctly displayed to the page.
What am I overlooking here and is there a better way to achieve this, for example obtaining the ip address from headers in _document.js?
req will only be available when getInitialProps is called on the server. This is why it works when you do a refresh on the page.
When navigating to the page there is no server render so getInitialProps will be called on the client. Therefore, req will be undefined.
You can wrap the assignment in a condition to check if req is defined to prevent the error:
Item.getInitialProps = async ({ req }) => {
let userIP
if (req) {
userIP = req.headers['x-real-ip'] || req.connection.remoteAddress
}
return { userIP }
}
However, if you want to have userIP available on every page, regardless of whether it's server or client rendered, then you will need to find a way to store it on first load, whichever page that may be.
Perhaps you could store it using context.
There is am example of using context here:
https://github.com/zeit/next.js/tree/master/examples/with-context-api
I hope this helps.

Resources