React init carousel jQuery lib with useEffect - reactjs

I'm working on a project on which I have to switch a classic website (HTML/JS) to React.
This is going pretty well except that I have a problem with the initialization of a carousel (jQuery library) ...
To be clear, I have several components (Children structure below):
-- Home
---- TopProducts
-------- ProductsSlider
--------------- Product
So in the Home component, I integrate the TopProducts component which makes an API call via Axios to get a list of products and passes the result to the ProductsSlider component.
This work well.
Once the API call is finished and the component generated, I need to initialize a carousel by a jquery function.
And this only works if I place the call to this function in the axios ".then" function below the addition to a state variable of the result of the call.
Like that :
useEffect(() => {
axios.get('products/bestsellers')
.then(response => {
setTopProducts(response.data.response);
window.carousel_slider();
});
}, []);
But it is very not clear to have it here( if i have another carousel in the page ... ), so I would like to have the call to this function in my Home component, but it does not work because the useEffect of Home is always called before the rendering of the TopProducts component ...
So i don't know how to call it when everything is rendered, i see that with Class component, the ComponentWillUnmount should work but i would like to use Hooks ...
I know that it is preferable not to use jQuery with React but it would be much too long to convert everything and to look for jquery libraries which does not exist maybe on react ...
I don't know if I have the right way, someone have an idea?
Thank you in advance

if you wrap your axios call in a return, it will behave like componentWillUnmount.
useEffect(() => {
return () => {
axios.get('products/bestsellers')
.then(response => {
setTopProducts(response.data.response);
window.carousel_slider();
});
}
}, [yourDependency]);

I found the problem.
It is because topProducts state is init with empty array and React don't wait the end of useEffect before rendering it, so the carousel_slider() is executed with the empty component.
Just need to check the topProducts state length before rendering :
{topProducts.length > 0 ? (
<ProductsSlider products={topProducts}/>
) : <Spinner />}

Related

How to implement promise when updating a state in functional React (when using useState hooks)

I know similar questions are bouncing around the web for quite some time but I still struggle to find a decision for my case.
Now I use functional React with hooks. What I need in this case is to set a state and AFTER the state was set THEN to start the next block of code, maybe like React with classes works:
this.setState({
someStateFlag: true
}, () => { // then:
this.someMethod(); // start this method AFTER someStateFlag was updated
});
Here I have created a playground sandbox that demonstrates the issue:
https://codesandbox.io/s/alertdialog-demo-material-ui-forked-6zss6q?file=/demo.tsx
Please push the button to get the confirmation dialog opened. Then confirm with "YES!" and notice the lag. This lag occurs because the loading data method starts before the close dialog flag in state was updated.
const fireTask = () => {
setOpen(false); // async
setResult(fetchHugeData()); // starts immediately
};
What I need to achieve is maybe something like using a promise:
const fireTask = () => {
setOpen(false).then(() => {
setResult(fetchHugeData());
});
};
Because the order in my case is important. I need to have dialog closed first (to avoid the lag) and then get the method fired.
And by the way, what would be your approach to implement a loading effect with MUI Backdrop and CircularProgress in this app?
The this.setState callback alternative for React hooks is basically the useEffect hook.
It is a "built-in" React hook which accepts a callback as it's first parameter and then runs it every time the value of any of it's dependencies changes.
The second argument for the hook is the array of dependencies.
Example:
import { useEffect } from 'react';
const fireTask = () => {
setOpen(false);
};
useEffect(() => {
if (open) {
return;
}
setResult(fetchHugeData());
}, [open]);
In other words, setResult would run every time the value of open changes,
and only after it has finished changing and a render has occurred.
We use a simple if statement to allow our code to run only when open is false.
Check the documentation for more info.
Here is how I managed to resolve the problem with additional dependency in state:
https://codesandbox.io/s/alertdialog-demo-material-ui-forked-gevciu?file=/demo.tsx
Thanks to all that helped.

which function is called when screen is returned from other screen in react native?

I can see the React native component life cycle. componentDidMount, UNSAFE_componentWillMount, etc
I thought UNSAFE_componentWillMount is called when screen is resumed. But it is not called.
I use React 17 over, React Native 0.68.1, and I use navigation.goBack() to return from second screen to first screen.
Which function is called when screen is resumed? Or what other way to do that?
You need to be careful here. In react-native a screen remains mounted on navigation. This differs from the web.
If you are coming to react-navigation from a web background, you may assume that when user navigates from route A to route B, A will unmount (its componentWillUnmount is called) and A will mount again when user comes back to it. While these React lifecycle methods are still valid and are used in react-navigation, their usage differs from the web.
Hence, if you navigate via goBack, the componentWillMount will not be called again, since the screen remains mounted. There is a general workaround for this problem which is documented here in the React Navigation lifecycle events section.
For functional components, we can use the useFocusEffect hook as follows.
useFocusEffect(
React.useCallback(() => {
// Do something when the screen is focused
return () => {
// Do something when the screen is unfocused
// Useful for cleanup functions
};
}, [])
);
For class components, we can use a focus listener. This is documented here.
class SomeClassComponent extends React.Component {
componentDidMount() {
this._unsubscribe = navigation.addListener('focus', () => {
// do whatever
});
}
componentWillUnmount() {
this._unsubscribe();
}
...
In some cases it might be more convenient to still use functional components. We can simply wrap a legacy class component into a functional component as follows.
const Wrapper = () => {
// useFocusEffect from above.
return <SomeClassComponent />
}
In react native when you change screen and come back to the previous screen it doesn't rerenders so using useEffect hook doesen't work. However you can use useFocusEffect hook provided by the react navigation. You can read more in details Here

Alert Automatic Disappear function

My aim is to give the user to see the alert at starting of the my page without clicking any button.And after a while it should be disappear automatically i am trying this on reactjs so any body help me out to find which logic should i apply
First render your alert component. Define a boolean state variable with initial value false.
then update that state variable with setTimeout.
import React, { useState, useEffect } from "react";
export const Alert = () => {
const [timeIsUp, setTimeIsUp] = useState(false);
useEffect(() => {
setTimeout(() => {
setTimeIsUp(true);
}, 5000);
}, []);
if (timeIsUp) {
return null;
}
return <div>your actual alert component content</div>;
};
You can refer this link: custom-modal-popup-component
Also just make the state of modal true at fist and add a setTimeout in useEffect and make it to false after a desired time.
Are you using class components or functional components for rendering your React page?
What you're looking for is called life cycles, i highly recomend you taking a look in ReactJS life cycle docs.
The life cycle method that executes or do something when the page is loaded has two usages:
If you're using class components, there is a native method you can call inside your component called ComponentDidMount(), his usage is available in docs here.
Now, if you're using functional components, you need to take a look on useEffect in React Hooks.
After that, you can take a look in setTimeout native method from javascript as observed.
Hope this helps too!

How to force refresh of GrandParent component from grandchild component with React hooks in SPFx

In the main component of a SPFx web part, I have a data load running in a React.useEffect
const [jobsGets, setJobsGets] = React.useState(0);
React.useEffect(() => {
{Some code to get data from SharePoint}
});
}, [jobsGets]);
So a refresh will happen when the value of "jobsGets" will change, right?
This component calls another component that calls another and the last has an event that should refresh by changing "jobsGets".
If I write a fanction and pass it down the props of each generation's component,
It ends running in the main component forever. So this is not a good solution.
How do I setJobsGets(jobsGets+1); from the grandchild components?
Any hint is welcome.
Thank you
you are likely updating jobs at grandChild with useEffect, that runs on mount and every update. if you pass a second empty array [] param, this update will run only after first render if that's your specific case, avoiding retriggers:
// at some granchild
useEffect(() => { ...logic here }, [])
if useEffect should run after on specific param's update, you pass that param as argument to the array. useEffect will run only on changes for the params dependencies set on [].
useEffect(() => { ...logic here }, [param])
you may also look at useContext for passing down state better at deep tree.

Where to Put Code that should run First ReactJs + Mobx State Tree

I have some code that grabs the users ipAddres. I do this right now in my componentDidMount in my app.js
async componentDidMount() {
await eventTrackingStore.getIpAddress();
}
So I did it in my app.js as it is my root component and I only want to set this once. This works fine if the user starts from the home page and navigates through the site.
However some pages can be loaded directly(ie you type in the url in your browser and it goes straight to that page).
Since the react lifecycle starts with most immediate component, which calls a method that expects the ipAddress code to be set but it does not get set till it hits the app.js
Now I could put the above code in each method but that gets tedious. Is there some sort of method in reactjs, or mbox or mbox state tree that would fire first?
If you use mobx-state-tree and you have a global store, then that global store can make the API call in the afterCreate method
const AppModel = types.model({
ips: types.array(types.string)
}).actions(self => ({
afterCreate() {
flow(function*() {
const ips = yield eventTrackingStore.getIpAddress();
self.setIps(ips)
})()
},
setIps(ips: string[]) {
self.ips = ips
}
}))
OR
The same thing you can do in a wrapped react component that wrappes every page of your app.
class App extends React.Component {
componentDidMount() {
eventTrackingStore.getIpAddress().then(res => {
// set the ips into a store or any logic you want in order to pass them down to children
})
}
render() {
return this.props.children
}
}
I can think of two solutions:
You can use react context
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
Use context to share the store between all components and if the data is not loaded, initialize loading right there in that nested component.
If the data is already there then just take it,
getIpAddress method should return a promise, so in case when data is already there it will be immediately resolved.

Resources