I'm new in ReactJS. Now trying to make the GET request from an API using axios with the following code. But page loads earlier than the request so my state gives an empty array. I tried to solve it by using async and await but I couldn't succeed it since I don't know the React well, I guess. Please help, thank you a lot.
import {useEffect, useState} from 'react';
import axios from 'axios';
function NewsPage(){
const [news, setNews] = useState([]);
useEffect(() => {
var axios = require("axios").default;
var options = {
method: 'GET',
url: 'https://api.newscatcherapi.com/v2/search',
params: {q: 'obama', lang: 'en', sort_by: 'relevancy', page: '1'},
headers: {
'x-api-key': '**************'
}
};
axios.request(options)
.then(function (response) {console.log(response.data.articles)})
.then(response => setNews(response.data.articles))
.catch(function (error) {console.error(error)})
},[]);
return (
<div>
Hello
{news.map((eachnews) => {
return <div key={eachnews.title}>
<h2>{eachnews.author}</h2>
</div>
})}
</div>
)
}
export default NewsPage
This is normal behavior of React. Older frameworks block the whole page while loading, but React renders the page already while loading.
It is a design decision that makes perfectly sense. You can add a loading animation or a skeleton during loading. This is considered better practice instead of leaving the whole page white. Especially because you can then do good error handling that doesn't interrupt the UI.
Related
The question is simple. How to fetch data in your React blog and stay DRY? Let's say that you have just two components in your blog - PostsList and SinglePost, in both components you must fetch data, activate isLoading state, etc. There will be chunks of the same code in both components.
I investigated the situation a little bit, checking React-blog demo apps of big headless CMS providers, like Prismic or Sanity.io, and they all just repeat fetch functions in both PostsList and SinglePost.
Does anybody have any idea? You can point me to some good resources?
You can achieve this by using High Order Components. You can use them for reusing component logic. Let me show you an example of how to handle the isLoading with a HOC:
HOC:
import React, { useState } from 'react'
const hocLoading = (WrappedComponent, loadingMessage) => {
return props => {
const [ loading, setLoading ] = useState(true)
const setLoadingState = isComponentLoading => {
setLoading(isComponentLoading)
}
return(
<>
{loading && <p>{loadingMessage}</p>} //message showed when loading
<WrappedComponent {...props} setLoading={setLoadingState} />
</>
)
}
}
export default hocLoading
As you can see this HOC is receiving the WrappedComponent and a message that you can set depending on your component. Then you will have to wrap every component where you want to show the loading feedback with the HOC and you can use the setLoading prop to stop showing the loading feedback:
const Component = props => {
const { setLoading } = props
useEffect(() => {
const loadUsers = async () => {
await fetchData() // fetching data
setLoading(false) // this function comes from the HOC to set loading false
}
loadUsers()
},[ ])
return (
<div className="App">
{usuarios.data.map(x => <p key={x.id}>{x.title}</p>)}
</div>
);
}
export default hocLoading(Component, "Data is loading") //component wrapped
// with the HOC and setting feedback message
This way you avoid repeating this process for every component. Regarding the data fetching you can create a Hook or a function that receives dynamic params so you can just call something like fetchData(url). Here is an example of a dynamic function for making request using axios:
const baseUrl = "" //your BASE URL
async function request(url,method,data){
try {
const response = await axios({
method,
url: `${baseUrl}${url}`,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
data: data ? data : undefined
})
return response
} catch (e) {
// handle error
}
}
I am trying to create a translation page where you type the word and it should translate to the language you chose in the dropdown. Using React and axios and the API from Rapid API.
I keep getting error like 401, 429 I know what the errors are but don't know how to fix it. Could it be from the website [Rapid API][1] that gives me a bad API?
import axios from "axios"
// de-structure language and text props
const Convert = ({ language, text }) => {
const [results, setResults] = useState("")
useEffect(() => {
const translate = async () => {
const translation = await axios.post(
"https://google-translate1.p.rapidapi.com/language/translate/v2",
{},
{
params: {
q: text,
target: language.value,
key: "cd4662825bmshfb23e36cc668d7fp111f42jsn736f6cc3a9aa",
},
}
)
setResults(translation.data.data.translations[0].translatedText)
}
translate()
}, [language, text])
console.log(results);
return (
<div>
<p>{results}</p>
</div>
)
}
export default Convert ```
[1]: https://rapidapi.com/googlecloud/api/google-translate1?endpoint=apiendpoint_a5764907-04b6-4d61-869b-79dc5325c739
I think there are 2 different APIs here... You are talking about the RapidAPI API but in the code you are using the MyMemory API.
So, regarding to your code and the MyMemory API specification, I see a couple errors in your code:
You are calling the /status endpoint, which checks the status of a TM import. I think this is not the endpoint you want to call. Instead, you have to make the request to the /get endpoint: https://api.mymemory.translated.net/get.
Also the request should be a get, not a post (just replace axios.post with axios.get).
The "q" and "key" params are correct, BUT in the documentation it says that you have to send a "langpair" param, not a "target".
With those changes the code should go fine. I've tried it and it works.
Try the next code:
import React, { useState, useEffect } from "react"
import axios from "axios"
import qs from "qs"
// de-structure language and text props
const Convert = ({ language, text }) => {
const [results, setResults] = useState("")
useEffect(() => {
const translate = async () => {
const translation = await axios.post(
"https://google-translate1.p.rapidapi.com/language/translate/v2",
qs.stringify({
q: text,
target: language.value
}),
{
headers: {
'x-rapidapi-key': 'cd4662825bmshfb23e36cc668d7fp111f42jsn736f6cc3a9aa',
'x-rapidapi-host': 'google-translate1.p.rapidapi.com'
}
}
)
setResults(translation.data.data.translations[0].translatedText)
}
translate()
}, [])
console.log(results);
return (
<div>
<p>{results}</p>
</div>
)
}
export default Convert
If you get a 403 Forbidden error then it's possibly because you're not subscribed to the API. To fix this, just go to https://rapidapi.com/googlecloud/api/google-translate1 and click on the "Subscribe to Test" button. Then select the free plan and you will be ready to go.
Here are some points that can definitely solve this issue.
If you're using RapidAPI then x-rapidapi-key is your API key. So instead of mentioning key in params, you can pass x-rapidapi-key inside the headers.
The possible reason for the 403 code is that you're not subscribed to that particular API. Make sure to double-check that.
429 status code indicates so many request in the give amount of time. I have checked, the rate limit is 5 request per second for Google Translate API.
You can use the code snippet that RapidAPI provides in order to avoid any kind of unwanted errors.
My back-end server is up and running. No problems on that side.
But on my front-end, when I load into the page containing the stripe checkout button, I get the error. And when I click on the button I get a bunch of "failed to load resource" errors. I'm not sure how to expand on this error, the error is accompanied with a long url which I'll append at the bottom. I have gone through the internet and was not able to find a similar issue with a solution.
my component below:
import React from 'react';
import StripeCheckout from 'react-stripe-checkout';
import axios from 'axios';
const StripeCheckoutButton = ({ price }) => {
const priceForStripe = price * 100;
const publishableKey = 'pk_test_6y*************';
const onToken = token => {
axios({
url: 'payment',
method: 'post',
data: {
amount: priceForStripe,
token: token
}
})
.then(response => {
alert('Payment Successfull!');
})
.catch(error => {
console.log('Payment Error: ', console.log(error.message));
alert('There was an issue with your Payment! Please use the provided credit card info.');
});
}
return (
<StripeCheckout
label='Pay Now'
name='Crown Clothing Ltd.'
billingAddress
shippingAddress
image='https://sendeyo.com/up/d/f3eb2117da'
description={`Your total is $${price}`}
amount={priceForStripe}
panelLabel='Pay Now'
token={onToken}
stripeKey={publishableKey}
/>
);
}
export default StripeCheckoutButton;
the urls in the error:
https://q.stripe.com/?event=checkout.config.summary&rf=http%3A%2F%2Flocalhost%3A3000%2Fcheckout&sc=&optchecker-origin=configure&optchecker-numErrors=0&optchecker-numWarnings=0&distinct_id=5bc50a5a-d3bc-56aa-9c8c-1e091f6a7712&eventId=f70f82d3-6f6d-21f9-cb99-9cc0594e70e5&option-key=pk_test_6yhlzR96RC4tBigWRKiPtlIV00iuUf9b6m&h=768&w=1366&lsid=53b5a4be-b37f-4749-9ed6-f33ce3db38e2&cid=de787f0d-a3c9-46d3-95a7-efb4b79d7894&i=1580345068891
https://q.stripe.com/?event=checkout.config.summary&rf=http%3A%2F%2Flocalhost%3A3000%2Fcheckout&sc=&optchecker-origin=configure&optchecker-numErrors=0&optchecker-numWarnings=0&distinct_id=5bc50a5a-d3bc-56aa-9c8c-1e091f6a7712&eventId=f70f82d3-6f6d-21f9-cb99-9cc0594e70e5&option-key=pk_test_6yhlzR96RC4tBigWRKiPtlIV00iuUf9b6m&h=768&w=1366&lsid=53b5a4be-b37f-4749-9ed6-f33ce3db38e2&cid=de787f0d-a3c9-46d3-95a7-efb4b79d7894&i=1580345068891
edit: since i've posted the question, i have tried to run my project from two other PCs and it works alright there. seems to be an issue with my own laptop. i believe it might have to do with an adblock of some kind. i have always had problem with loading ads for some reason, even though i don't have any adblock installed
I am trying to get data from the API by using POST Method, However, I am struggling to set the data into post
import { useRouter } from 'next/router';
import Layout from '../../components/MyLayout';
import Settings from '../../components/Settings';
const Post = props =>{
//works if I use here
const router = useRouter();
return (
<Layout>
<h1>{router.query.id}</h1>
<p>This is the blog post content.</p>
</Layout>
);
}
export default Post;
Post.getInitialProps = async function(){
//trying to get data ($_GET)
const router = useRouter();
const data = router.query;
//
const FormData = new URLSearchParams();
const res = await fetch(Settings.api+'viewPost',{
method: 'POST',
headers:{
'Content-Type': 'application/x-www-form-urlencoded',
},
body: FormData,
});
const obj = await res.json();
return(
obj
);
}
I receive this following error
Invalid hook call. Hooks can only be called inside of the body of a
function component. This could happen for one of the following
reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app See *** for tips about how to debug and
fix this problem.
I just learn about this, sorry for the dumb question. I really appreciate any answer. Thank you.
I did the exact same thing (try to use useRouter in getinitialProps) as you and get the same error just now, then I search around and found how to get query string parameter in next , so to answer your question , you don't need useRouter in this case but instead use getInitialProps (props) and find the query params to get your data or Id or whatever. Hope that helps.
Post.getInitialProps = async function({ query }){
const { data } = query;
...................
}
I am new to rxjs Observables. I am trying simple login page application. When I am sending correct credentials, code is working fine and loading spinner also stops rendering. When credentials are invalid then code stops working and spinner also stays on the page. I have to reload the page to make it work again.
Here's the code :
import constants from "../constants";
import "rxjs";
import { ajax } from "rxjs/observable/dom/ajax";
import { loginBody } from "../utils/bodyCreator";
import {
showLoadingSpinner,
hideLoadingSpinner
} from "../actions/LoadingOverlayActions";
const sessionCreated = payload => ({
type: constants.sessionCreated,
response: payload
});
export const tryLoginEpic = (action$, store) =>
action$
.ofType(constants.tryLogin)
.map(() => store.dispatch(showLoadingSpinner()))
.mergeMap(action =>
ajax
.post(constants.loginEndPoint, loginBody(store.getState()), {
"Content-Type": "application/json"
})
.map(data => store.dispatch(sessionCreated(data.response)))
.map(() => store.dispatch(hideLoadingSpinner()))
.catch(err => store.dispatch(hideLoadingSpinner()))
);
Please help me how to do this and what is wrong in this code?
Thanks
You need to use .catch operator in a different way. For example, return empty Observable (or other action), something like:
.catch(error => {
store.dispatch(hideLoadingSpinner());
return Observable.empty();
})
see official documentation on catchError operator