Get all products woocommerce rest api react native - reactjs

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.

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.

React native axios crashing and werid behaviour

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))

Issue with pushing data into firebase

Here I'm trying to push the data inside the array in Firebase, but it's pushing the data continuously until the cache from the app is destroyed. Here is my code and Firebase screenshot.
code:
var Input = {
AaMessage: 'brb',
}
var query = firebase.database().ref('UserList/');
query
.orderByChild('PostId')
.equalTo(this.state.PostID)
.on('value', snapshot => {
snapshot.forEach(child => {
firebase
.database()
.ref('UserList/' + child.key + '/Paymentdetails')
.push(Input)
.then(resp => {
console.log('Done', resp);
})
.catch(err => {
console.log('Error', err);
});
});
});
Firebase view:
You're opening a listener which writes to the same node it listens to. Even if that's not causing recursion, you're still writing a new doc for every child every single time your UserList is updated.
Also, avoid mixing lists and documents in a single rt-db node. That can only lead to pain.
It's difficult to understand what you are trying to do -- but it looks like you might want to call once instead of on, so the listener doesn't stay open and keep writing (potential lots of) new documents.
Additionally, I would recommend not writing to the node you're listening to.
database().ref("SomewhereElse/").push(doc);
I don't know why you would want to push new docs whenever the snapshot updates, you're going to get a lot of duplicates. If that was a mistake you likely want to do those pushes in a onCreate trigger.

A more performance-friendly way to use setInterval() in componentDidMount when fetching data

i am struggling pretty hard here to find the right solution. Currently, I am using setInterval() to "poll" my server and retrieve an array of objects. To fetch the data, I am using axios. Here are the pertinent functions:
componentDidMount(){
this.timer = setInterval(() => [this.getData(), this.getCustData()], 1000);
}
componentWillUnmount(){
this.timer && clearInterval(this.timer);
this.timer = false
}
getData = () => {
axios.get('http://localhost:3001/api/v1/pickup_deliveries')
.then((response) => {
this.setState({
apiData: response.data
})
})
.catch((error)=>{console.log(error);});
}
getCustData = () => {
axios.get('http://localhost:3001/api/v1/customers')
.then((response) => {
this.setState({
custData: response.data
})
})
.catch((error)=>{console.log(error);});
}
The application is running so slow and often times, it will completely hang the server which makes the whole application unusable. Currently the array it's fetching has over 1000+ objects and that number is growing daily. If I fetch the data without polling the server, the feel of my application is night and day. I am not quite sure what the answer is but I do know what I am doing is NOT the right way.
Is this just the nature of mocking "polling" with setInterval() and it is what it is? Or is there a way to fetch data only when state has changed?
If I need to implement SSE or WebSockets, I will go through the hassle but I wanted to see if there was a way to fix my current code for better performance.
Thanks for hearing me out.
On the frontend side, my advice would be to not use setInterval, but use setTimeout instead.
Using setInterval, your app might send another request even if the response for previous request hasn't come back yet (e. g.: it took more than 1 second). Preferably, you should only send another request 1 second after the previous response is received.
componentDidMount() {
getData();
}
getData = () => {
fetch().then(() => {
updateState();
// schedule next request
setTimeout(getData, 1000);
});
}
You should also try to reduce the amount of updates that need to be done on the frontend, for example by reducing the number of the data.
But nevertheless, I think the most important is to rethink the design of your application. Polling huge JSON that is going to only grow bigger is not a scalable design. It's bad for both the server and the client.
If what you are trying to do is to have the client be notified of any changes in the server side, you should look into WebSocket. A simple idea is that the browser should establish a WS connection to the server. Upon any updates to the server, instead of sending down the whole data, the server should only send down the updates to the client. The client would then update its own state.
For example, let's say 2 users are opening the same page, and one user make changes by adding a new Product. Server will receive this request and update the database accordingly. It will also broadcast a message to all open WebSocket connections (except for the one connection that added the Product), containing a simple object like this:
{
"action": "INSERT",
"payload": {
"product": {
"id": 123123,
... // other product data
}
}
}
The other user will use this data to update its own state so it matches the server.

Resources