React native axios crashing and werid behaviour - reactjs

Axios is behaving weird on my react native webview if you have any idea how to solve or how i can track the problem it would be of much help.
On the onMessage of the webview i recieve the html of the website so i can get a specific link. I send the message when the user taps anywhere on screen.
Injected js:
var body_of_html = document.body;
body_of_html.addEventListener('click',function(e){
window.ReactNativeWebView.postMessage(document.documentElement.innerHTML)
},false);
Case 1
This doesnt console.log anything and after some time crashes the app.
onMessage={event => {
// console.log('asdas');
var regex = new RegExp('token=[a-zA-z0-9]+');
if (event.nativeEvent.data.toString().match(regex) != null) {
let asd =
'https://fvs.io/redirector?' +
event.nativeEvent.data.toString().match(regex);
axios.get(asd).then(rs => {
console.log(rs);
});
Case 2
This one works perfectly fine and logs "Anything".
onMessage={event => {
var regex = new RegExp('token=[a-zA-z0-9]+');
if (event.nativeEvent.data.toString().match(regex) != null) {
let asd =
'https://fvs.io/redirector?' +
event.nativeEvent.data.toString().match(regex);
axios.get(asd).then(console.log("Anything"));
As you can see from the above cases i am unable to get the response from the axios call. Which always after some time crashes the app. Am i doing something wrong on reciving the response ?
Edit: I think I know what might have caused my application to crash but this is just what I found after looking at the data consumed. The link i was sending to the axios.get was retriving bits of a video until it fully buffered. But the way my code was , it would do this action each time i tapped the screen. I guess at some point axios couldnt handle reciving 10x + videos at 1080p at the same time. Just to clarify my intention was just to get the redirection link i didnt know it would cause the video to buffer.

As in all promises, in order to debug the error, e.g. in cases where event.nativeEvent.data may be undefined, causing .toString() to throw error, use a catch block.
axios.get(asd).then(rs => {
console.log(rs);
}).catch(error => console.log("error from axios", error))

Related

Handling OAuth with React 18 useEffect hook running twice

Background
I have recently upgraded a fairly sizeable React app to React 18 and for the most part it has been great. One of the key changes is the new double mount in development causing useEffect hooks to all run twice, this is clearly documented in their docs.
I have read their new effect documentation https://beta.reactjs.org/learn/lifecycle-of-reactive-effects and although it is quite detailed there is a use case I believe I have found which is not very well covered.
The issue
Essentially the issue I have run into is I am implementing OAuth integration with a third-party product. The flow:
-> User clicks create integration -> Redirect to product login -> Gets redirected back to our app with authorisation code -> We hit our API to finalise the integration (HTTP POST request)
The problem comes now that the useEffect hook runs twice it means that we would hit this last POST request twice, first one would succeed and the second would fail because the integration is already setup.
This is not potentially a major issue but the user would see an error message even though the request worked and just feels like a bad pattern.
Considered solutions
Refactoring to use a button
I could potentially get the user to click a button on the redirect URL after they have logged into the third-party product. This would work and seems to be what the React guides recommend (Although different use case they suggested - https://beta.reactjs.org/learn/you-might-not-need-an-effect#sharing-logic-between-event-handlers).
The problem with this is that the user has already clicked a button to create the integration so it feels like a worse user experience.
Ignore the duplicate API call
This issue is only a problem in development however it is still a bit annoying and feels like an issue I want to explore further
Code setup
I have simplified the code for this example but hopefully this gives a rough idea of how the intended code is meant to function.
const IntegrationRedirect: React.FC = () => {
const navigate = useNavigate();
const organisationIntegrationsService = useOrganisationIntegrationsService();
// Make call on the mount of this component
useEffect(() => {
// Call the method
handleCreateIntegration();
}, []);
const handleCreateIntegration = async (): Promise<void> => {
// Setup request
const request: ICreateIntegration = {
authorisationCode: ''
};
try {
// Make service call
const setupIntegrationResponse = await organisationIntegrationsService.createIntegration(request);
// Handle error
if (setupIntegrationResponse.data.errors) {
throw 'Failed to setup integrations';
}
// Navigate away on success
routes.organisation.integrations.navigate(navigate);
}
catch (error) {
// Handle error
}
};
return ();
};
What I am after
I am after suggestions based on the React 18 changes that would handle this situation, I feel that although this is a little specific/niche it is still a viable use case. It would be good to have a clean way to handle this as OAuth integration is quite a common flow for integration between products.
You can use the useRef() together with useEffect() for a workaround
const effectRan = useRef(false)
useEffect(() => {
if (effectRan.current === false) {
// do the async data fetch here
handleCreateIntegration();
}
//cleanup function
return () => {
effectRan.current = true // this will be set to true on the initial unmount
}
}, []);
This is a workaround suggested by Dave Gray on his youtube channel https://www.youtube.com/watch?v=81faZzp18NM

How to implement API call to server and display data on button click (React, Node, Express)

EDIT: I've debugged and provided an answer to some of my issues below.
I've been researching this issue for a while now and can't seem to find an adequate resolution. As you will see looking at my code, I have a lot to learn. The issue seems to come from trying to display data that hasn't finished fetching despite my redundant placement of await. I am also curious if I should place my getData() function within a useEffect hook? The problem with this is I use the getData() function in my submit button's onClick. So when I run my app, getData() is only available in useEffect's scope.
const getData = async () => {
if(searchData.platform !== "" && searchData.platformUserIdentifier !== ""){
setValidInput(true);
const response = await fetch(`http://localhost:8080/data?platform=${searchData.platform}&username=${searchData.platformUserIdentifier}`);
const json = await response.json();
await finishAllOperations(json)
} else {
setValidInput(false);
}
}
function finishAllOperations(json) {
if(json.code === "ERR_BAD_REQUEST"){
console.log(`Request failed with a status code ${json.status}`);
setErrorMessage(true);
setDisplayTable(false);
} else {
console.log("Request successful");
setMatches(json);
setErrorMessage(false);
setDisplayTable(true)
}
}
const displayMatchRows = matches.map((match,index) => {
//dummy data to populate if reward is available
function checkRewardAvailability(match){
const value = Math.random()
if (value <= .5) {
return true
} else {
return false
}
}
return (
<tr key={match.id}>
<td>{index+1}</td>
<td>{parseDate(match.metadata.endDate.value)}</td>
<td>{match.stats.kills.value}</td>
<td>{match.stats.rankScore.value}</td>
<td>{checkRewardAvailability()?<button className="reward-button">Claim Reward</button>:""}</td>
</tr>
)
})
When I go to deploy my code to my Node server and attempt to submit an API call with the above code I receive the following error:
TypeError: b.map is not a function
Furthermore, when I run my program with my client and server running on separate terminals my code does work and the data does properly get displayed. However, the "Request successful" console log occurs before the fetch has finished running. Obviously, I would like for the "Request successful" (see attached screenshot) to occur after I have completely finished fetching all data.
"Request Success" before fetch finish
I really appreciate any input as on I'm the verge of smashing my computer. Thank you in advance.
I am happy to report after several hours of debugging, the error came from my .env file providing an undefined value because it was not getting moved alongside my package.json file.
Because the .env file was in the wrong place, I was not getting returned an array that .map would work on. Once I realized the error I was receiving had something to do with my server's API call, I was getting an error that went
{"code":"ERR_HTTP_INVALID_HEADER_VALUE"}
This seemed very vague to me and took a while to locate. If you're receiving this error and you are using a .env file, check to be sure it's not returning an undefined value. If it is undefined, then ensure that the .env files is in the same directory as your package.json file.

Get all products woocommerce rest api react native

I am trying build search function in my react native app to search in my woocommerce products (1000 products aprox)
here is my code
componentDidMount() {
let p=1;
while (p<11)
{console.log(p)
WooCommerce.get("products",{per_page:100,page:p})
.then((response) => {
p++;
allprod = allProd.concat(response)
}
)
.catch((error) => {
console.log(error.response);
});
}
i am getting this error
ExceptionsManager.js:173 Warning: Please report: Excessive number of pending callbacks: 501. Some pending callbacks that might have leaked by never being called from native code: {"1623":{"module":"NativeAnimatedModule","method":"startAnimatingNode"},"1865":{"module":"Networking","method":"sendRequest"},"1872":{"module":"Networking","method":"sendRequest"},"1879":{"module":"Networking","method":"sendRequest"},"1886":{"module":"Networking","method":"sendRequest"},"1893":
anyone have an idea about what i am doing wrong?? you help is much appreciated
Why do you need to fetch all the data on componentDidMount() ? And if so why don’t you simply fetch everything in one call( per_page:1000) ?
What happens here is that your while will run over and over again. WooCommerce.get is async so it wont wait until you increase p. If you still want to keep thing like this you could try to change that while in a for.

How to create and update a text file using React.js?

I am trying to save a variable's data into a text file and update the file every time the variable changes. I found solutions in Node.js and vanilla JavaScript but I cannot find a particular solution in React.js.
Actually I am trying to store Facebook Long Live Access Token in to a text file and would like to use it in the future and when I try importing 'fs' and implementing createFile and appendFile methods I get an error saying Method doesn't exist.
Please help me out. Here is the code below
window.FB.getLoginStatus((resp) => {
if (resp.status === 'connected') {
const accessToken = resp.authResponse.accessToken;
try {
axios.get(`https://graph.facebook.com/oauth/access_token?client_id=CLIENT_id&client_secret=CLIENT_SECRET&grant_type=fb_exchange_token&fb_exchange_token=${accessToken}`)
.then((response) => {
console.log("Long Live Access Token " + response.data.access_token + " expires in " + response.data.expires_in);
let longLiveAccessToken = response.data.access_token;
let expiresIn = response.data.expires_in;
})
.catch((error) => {
console.log(error);
});
}
catch (e) {
console.log(e.description);
}
}
});
React is a frontend library. It's supposed to be executed in the browser, which for security reasons does not have access to the file system. You can make React render in the server, but the example code you're showing is clearly frontend code, it uses the window object. It doesn't even include anything React-related at first sight: it mainly consists of an Ajax call to Facebook made via Axios library.
So your remaining options are basically these:
Create a text file and let the user download it.
Save the file content in local storage for later access from the same browser.
Save the contents in online storage (which could also be localhost).
Can you precise if any of these methods would fit your needs, so I can explain it further with sample code if needed?

AngularJS and BrightCove Media API

I am working on integrating BrightCove into an Ionic App (allows HTML and JS/Angular to run as a native app on mobile devices).
The app will play videos and allow user's to download the video to save the user's device, I can get the app to play the video but am having issues getting the
Media API to run the 'find_video_by_id' call.
So I have a download button which triggers the following function
_this.downloadBrightcoveVideo = () => {
let searchParams = {}
BCMAPI.token = 'xxxx..'
BCMAPI.callback = 'useDownloadLink'
BCMAPI.command = 'find_video_by_id'
searchParams.video_id = 1234567890
searchParams.media_delivery = 'HTTP'
searchParams.video_fields = 'FLVURL'
BCMAPI.find (BCMAPI.command, searchParams)
}
where token and video_id are set to my video and URL Access token.
I have tried setting the useDownloadLink function as below
let useDownloadLink = function () { console.log ("I'm Alive") }
or
function useDownloadLink () { console.log ("I'm Alive") }
or
_this. useDownloadLink = () => { console.log ("I'm Alive") }
Every time I run the code I get the error below, even though I have useDownloadLink above the download function
Uncaught ReferenceError: useDownloadLink is not defined
I have tried several variations now and nothing is working, any solution would be gratefully received.
Thanks in advance,
Áine
So after a bit of Google-ing came to the conclusion it was better to use BrightCove's CMS Api to achieve the results I wanted, once going through the api it was actually pretty simple..
Hope that helps someone else :D
Happy Coding!

Resources