I have installed swiper slider (react version) and created a custom block. When I add the block in the backend it works swimmingly and I can swipe just fine. But when I save and view in the frontend nothing appears. When I check the error messages after refreshing in the backend I see this message:
Uncaught 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:
- You might have mismatching versions of React and the renderer (such as React DOM)
- You might be breaking the Rules of Hooks
- You might have more than one copy of React in the same app
import { registerBlockType } from "@wordpress/blocks";
import { useBlockProps } from "@wordpress/block-editor";
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/css";
import "./editor.scss";
import "./style.scss";
import json from "./block.json";
import { __ } from "@wordpress/i18n";
const { name, ...settings } = json;
registerBlockType(name, {
...settings,
edit: (props) => {
return (
<div {...useBlockProps()}>
<Swiper
spaceBetween={50}
slidesPerView={3}
onSlideChange={() => console.log("slide change")}
onSwiper={(swiper) => console.log(swiper)}
>
<SwiperSlide>Slide 1</SwiperSlide>
<SwiperSlide>Slide 2</SwiperSlide>
<SwiperSlide>Slide 3</SwiperSlide>
<SwiperSlide>Slide 4</SwiperSlide>
</Swiper>
</div>
);
},
save: () => {
return (
<div {...useBlockProps.save()}>
<Swiper spaceBetween={50} slidesPerView={3}>
<SwiperSlide>Slide 1</SwiperSlide>
<SwiperSlide>Slide 2</SwiperSlide>
<SwiperSlide>Slide 3</SwiperSlide>
<SwiperSlide>Slide 4</SwiperSlide>
</Swiper>
</div>
);
},
});
I have installed swiper slider (react version) and created a custom block. When I add the block in the backend it works swimmingly and I can swipe just fine. But when I save and view in the frontend nothing appears. When I check the error messages after refreshing in the backend I see this message:
Uncaught 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:
- You might have mismatching versions of React and the renderer (such as React DOM)
- You might be breaking the Rules of Hooks
- You might have more than one copy of React in the same app
import { registerBlockType } from "@wordpress/blocks";
import { useBlockProps } from "@wordpress/block-editor";
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/css";
import "./editor.scss";
import "./style.scss";
import json from "./block.json";
import { __ } from "@wordpress/i18n";
const { name, ...settings } = json;
registerBlockType(name, {
...settings,
edit: (props) => {
return (
<div {...useBlockProps()}>
<Swiper
spaceBetween={50}
slidesPerView={3}
onSlideChange={() => console.log("slide change")}
onSwiper={(swiper) => console.log(swiper)}
>
<SwiperSlide>Slide 1</SwiperSlide>
<SwiperSlide>Slide 2</SwiperSlide>
<SwiperSlide>Slide 3</SwiperSlide>
<SwiperSlide>Slide 4</SwiperSlide>
</Swiper>
</div>
);
},
save: () => {
return (
<div {...useBlockProps.save()}>
<Swiper spaceBetween={50} slidesPerView={3}>
<SwiperSlide>Slide 1</SwiperSlide>
<SwiperSlide>Slide 2</SwiperSlide>
<SwiperSlide>Slide 3</SwiperSlide>
<SwiperSlide>Slide 4</SwiperSlide>
</Swiper>
</div>
);
},
});
Share
Improve this question
asked Dec 26, 2021 at 15:22
user8463989user8463989
5931 gold badge8 silver badges24 bronze badges
2
- your save function isn't meant to return an operational react component that executes on the frontend, it's meant to return the raw static HTML that gets saved to the database. It's up to you to transform that into a swiper slider on the frontend in JS much like you would a widget or shortcode. There's also a super important part of the error message that you've not shared to try and be helpful which is the stack trace that shows you where and when the calls were made. – Tom J Nowell ♦ Commented Dec 26, 2021 at 15:42
- 1 You might also find that Swiper does not "support" react in the way that you expect it to, it's just a wrapper around a non-React implementation that uses DOM hoisting, so it may not be as portable as you'd hoped. This becomes super obvious when you try to implement nested blocks via a slide block, those slides aren't' recognised as slides and get moved to after the slide area as an "after block" area. I've made PR's to try to and fix this in swiper which improved things, but a fix isn't possible without a re-architecting of how the swiper react code works – Tom J Nowell ♦ Commented Dec 26, 2021 at 15:44
1 Answer
Reset to default 2You've misunderstood the purpose of the save component. The goal of the save component is not to return an interactive React component, it's to return something that can be converted into static HTML and saved in the database as a string in the post content.
Since only the HTML gets saved, it's your responsibility to load javascript on the frontend that finds this HTML and converts it into a Swiper slider.
So you should not attempt to do any of the following in the save component, directly or indirectly via a library:
- event listeners
- react state
- callbacks/effects/HTTP requests/etc
A save component can even be ran when no saving is occurring, for example when validating a block by comparing the saved block to the save component.
So with this in mind, it makes no sense to use <Swiper>
or <SwiperSlide>
components here.
Instead, follow the Swiper documentation and generate actual HTML instead:
<!-- Slider main container -->
<div class="swiper">
<!-- Additional required wrapper -->
<div class="swiper-wrapper">
<!-- Slides -->
<div class="swiper-slide">Slide 1</div>
<div class="swiper-slide">Slide 2</div>
<div class="swiper-slide">Slide 3</div>
...
</div>
<!-- If we need pagination -->
<div class="swiper-pagination"></div>
<!-- If we need navigation buttons -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
<!-- If we need scrollbar -->
<div class="swiper-scrollbar"></div>
</div>
https://swiperjs/get-started#add-swiper-html-layout
Adjust it for JSX and save it that way.
As an aside, the way the Swiper library detects the slides in the <Swiper>
component is by inspecting the virtual dom and looking for direct descendants of type <SwiperSlide>
. This means it cannot find the slides if you use Slide blocks. This means having user configurable slides is not possible in Gutenberg because of the higher order components used to provide block information. It's not possible to have nested blocks this way. Swiper will interpret child blocks as additional HTML to append after the slider, even if they're slides or <SwiperSlide>
components.