Swiperjs in React : swiper.slideTo TypeScript - reactjs

I am trying to use Swiperjs in my project, in a Typescript file. I want to change the active slide from another component (Tabs, from material UI, already in place). I can swipe directly in the Swiper component but I'd like to make that possible otherwise and elsewhere as well.
However I do not find the way to trigger the method slideTo (here the API) outside the component
...
<Swiper
onSlideChange={(swiper) => setValue(swiper.realIndex)}
...
>
Here my slides, other components, ...
</Swiper>
So ideally I'd rather like to have something like :
...
function handleExternalChangeSlide=(newSlideIndexToShow)=>{
swiper.slidesTo(newSlideIndexToShow)
}
<Swiper
onSlideChange={(swiper) => setValue(swiper.realIndex)}
...
>
Here my slides, other components, ...
</Swiper>
I have seen many people doing that:
var swiper = new Swiper('.swiper-container', {
... options
});
function handleExternalChangeSlide=(newSlideIndexToShow)=>{
swiper.slidesTo(newSlideIndexToShow)
}
)
But actually, Typescript claims that: Only a void function can be called with the 'new' keyword and I do not know how to handle that
Do you see any way to proceed to be able to change the active slide (without using pagination from Swiper) outside Swiper component in my .tsx file?

The Swiper component takes onSwiper props a function that will return you an instance of the created Swiper.
You can save this instance to a state and then call all the methods you need on it.
Here is one of the implementation options:
const [swiperInstance, setSwiperInstance] = useState<SwiperCore>();
const handleExternalChangeSlide = (newSlideIndexToShow) => {
swiperInstance.slidesTo(newSlideIndexToShow);
}
...
<Swiper
onSwiper={setSwiperInstance}
onSlideChange={(swiper) => setValue(swiper.realIndex)}
...
>
Here my slides, other components, ...
</Swiper>

Related

Render a react component inside leaflet's popup created in pointToLayer of react-leaflet's GeoJSON

I'm looking for a way to render a react component (e.g. mui's Link) inside a popup created in react-leaflet's pointToLayer function of the GeoJSON component. Alternatively, invoke a function by clicking <a> or <button> in the popup.
The code I'm using now kind of works – I could redirect a user to a different URL. The problem is that I want the link inside the popup to call a function (which will change react's state, e.g. opening mui's Drawer).
import L from "leaflet";
import geoJSON from "../resources/test.json";
function callMe() {
console.log("test") //will change state
}
function featureToCircle(feature, latlng) {
const pointName = "from feature";
const popup = L.popup().setContent(`
<p>${pointName} – (${latlng.lat}, ${latlng.lng})</p>
invoke callMe()
`);
//ideally: <Link href="#" onClick={() => callMe() }>invoke callMe()</Link>
return L.circleMarker(latlng, {
color: "yellow",
})
.bindPopup(popup)
.bindTooltip(pointName);
}
export default function MyGeoJSON(props) {
return (
<GeoJSON key="whatever" data={geoJSON} pointToLayer={featureToCircle} />
);
}
I tried with ReactDOMServer.renderToString – unfortunately, the onClick doesn't work with this approach.
I'm also aware that I could replace GeoJSON with separate tags, like here, and it should work. I treat it as the last resort, though, and would rather use GeoJSON, to avoid replicating its functionality.

How to start animation before component is removed in React?

I would like to know how do I trigger an animation before removing a functional React component.
I am using the npm package to manage animations via JS. So I just need to call the function. For example function animate.
import React from "react";
useEffect(() => {
function animateStart() {
console.log('AnimateStart')
}
},[]);
export default function () {
return(
<div className={'component'}/>
)
}
This is how I am triggering the animation when the component appears. I would like to somehow catch the removal and postpone it for the duration of the animation.
At the moment I'm calling the delete animation from the parent component. This forces me to store the animateExit function in another component. It is not comfortable :(
Try this:
useEffect(() => {
function animateStart() {
console.log('AnimateStart')
}
return () => {/* whatever you want to do, it will be called everytime when this component is unmounted*/}
},[]);

React init carousel jQuery lib with useEffect

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 />}

Typescript: How to suppress "No overload matches this call"?

So I have a React Native application that uses Native Base as UI lib and Typescript.
Now there is an Accordion which - as soon its expanded - renders a second (nested) Accordion. The problem is that TypeScript complains:
A VirtualizedList contains a cell which itself contains more than one VirtualizedList of the same orientation as the parent list. You must pass a unique listKey prop to each sibling list.
Which is perfectly fine. But when I add this listKey to my Accordion, TypeScript complains about No overload matches this call.
How can I suppress this warning? Because Native Base doesn't provide listKey as prop for their Accordion.
Here is the code:
imports ...
type Props = {};
const Test: React.FC<Props> = ({}) => {
const renderNestedAccordion = () => {
return (
<View>
<ComponentWithAccordion></ComponentWithAccordion>
</View>
);
};
const dataArray = [{content: renderNestedAccordion()}];
return (
<Accordion
listKey={'acc'} // error
dataArray={dataArray}
/>
);
};
export default Test;
Quick fix:
You can try //#ts-ignore which should suppress the warning.
For more
Less guilty solution:
If you look at NativeBase type definition for Accordion, you will see that there is no listKey. Under the hood, NativeBase Accordion uses a FlatList. We know from React Native type definition of FlatList extends VirtualizedListProps<ItemT> that has a listKey.
Look at the Accordion implementation we see that FlatList takes all props from Accordion which means all FlatList props should be supported. Therefore Accordion should extend FlatList props. You can add listKey to the Accordion type definition or send a Github issue.
Disclaimer: I have never used Native Base. The above conclusion is made by looking at the code.

Giving React component animation on mount

I am trying to make this component move in when mounted but getting
Cannot read property 'enter' of undefined
Here is a simplified code (I have all the CSS classes ready):
class Example extends React.Component {
state = {
transitionIn: false,
};
componentDidMount = () => {
this.setState({ transitionIn: true })
}
render() {
return (
<CSSTransition
in={this.state.transitionIn}
timeout={1000}
className={'wordTransition'}
>
<div>dksjfnsdkjnfj</div>
</CSSTransition>
);
}
}
https://codesandbox.io/s/rj5046zxoo
I believe that the error you were experiencing is one that you solved in the codesandbox.io link you provided above. I was having this same problem. Instead of naming the prop that takes a class name to be used as the prefix for the various transition states classNames (plural) I was using the more familiar className (singular).
To reiterate: inside the <CSSTransition> component, make sure you are using a classNames prop and not className as you would inside of a react component's html elements.
I feel that the choice on the part of the React Transition Group to use a prop called classNames in their component is confusing and should perhaps be reconsidered.

Resources