I'm building a react application, and on my HomePage, I have the component 'CategoriesList'.
When I'm on the HomePage, the 'Categories List' works well, but when I navigated to ProductDetails page with react-router-dom, I found this error:
"NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node."
'CategoriesList' uses Flickty. I tried to remove Flickity, and... Works well. But I need to use Flickity.
Can anyone help me?
CategoryList Component:
const CategoryList = ({list, popupOpen, refreshProductList}) => {
return (
<Container>
<Slider
options={{
cellAlign: 'center',
draggable: true,
groupCells: true,
contain: false,
pageDots: false,
}}
style={ popupOpen ? ({opacity: 0.05}) : null}
>
{list.map((category, index) => (
<Category key={index}>{category}</Category>
))}
</Slider>
</Container>
);
}
Flickty Slider Component:
import Flickity from 'flickity';
import 'flickity/dist/flickity.min.css';
export default class Slider extends Component {
constructor(props) {
super(props);
this.state = {
flickityReady: false,
};
this.refreshFlickity = this.refreshFlickity.bind(this);
}
componentDidMount() {
this.flickity = new Flickity(this.flickityNode, this.props.options || {});
this.setState({
flickityReady: true,
});
}
refreshFlickity() {
this.flickity.reloadCells();
this.flickity.resize();
this.flickity.updateDraggable();
}
componentWillUnmount() {
this.flickity.destroy();
}
componentDidUpdate(prevProps, prevState) {
const flickityDidBecomeActive = !prevState.flickityReady && this.state.flickityReady;
const childrenDidChange = prevProps.children.length !== this.props.children.length;
if (flickityDidBecomeActive || childrenDidChange) {
this.refreshFlickity();
}
}
renderPortal() {
if (!this.flickityNode) {
return null;
}
const mountNode = this.flickityNode.querySelector('.flickity-slider');
if (mountNode) {
return ReactDOM.createPortal(this.props.children, mountNode);
}
}
render() {
return [
<div style={this.props.style} className={'test'} key="flickityBase" ref={node => (this.flickityNode = node)} />,
this.renderPortal(),
].filter(Boolean);
}
}
If you want to use Flickity along with React instead of creating your own component, I highly recommend using react-flickity-component. It's also easy to use:
Tip: if you use wrapAround option in Flickity set
disableImagesLoaded prop ture (default is false).
import Flickity from 'react-flickity-component'
const flickityOptions = {
autoPlay: 4000,
wrapAround: true
}
function Carousel() {
return (
<Flickity
disableImagesLoaded
options={flickityOptions} // Takes flickity options {}
>
<img src="/images/placeholder.png"/>
<img src="/images/placeholder.png"/>
<img src="/images/placeholder.png"/>
</Flickity>
)
}
Related
Here I am getting some problems with AliceCarousel to map my response to display its images in the gallery.
I wanted to display the respective types of images for each gallery.
I am generally following SO example .
Any help or suggestion here to make it possible?
Thanks is advance.
//Js
class KitchenService extends Component {
constructor(props) {
super(props);
this.state = {
currentIndex: 0,
responsive: { 1024: { items: 3 } },
galleryItems: this.galleryItems(),
services : this.props.resume,
...props,
ItemsServices:[]
}
}
static propTypes = {
getService: PropTypes.func.isRequired,
resume: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired,
loading: PropTypes.object.isRequired
}
UNSAFE_componentWillReceiveProps(nextProps) {
if(nextProps.resume !== this.props.resume){
var services = this.props.resume.services;
this.setState({
ItemsServices: services
})
}
}
componentDidMount() {
this.props.getService();
}
slideTo = (i) => this.setState({ currentIndex: i })
onSlideChanged = (e) => this.setState({ currentIndex: e.item })
galleryItems = () => {
return this.state.ItemsServices.map((brand, i) => {
var checkImage = brand.length !== 0 && brand.service_name === "Office";
console.log(checkImage, "checkImage")
return (
<div key={`key-${i}`} className="card-img-top"><img src={brand.service_image_url} /></div>
)
})
};
render() {
const { responsive, currentIndex } = this.state
const items = this.galleryItems();
return(
<div>
<Grid className ="col-12 service-kitchen-gallery-grid" >
<div className="service-gallery-headline">
Kitchen
</div>
<AliceCarousel
dotsDisabled={true}
buttonsDisabled={true}
items={items}
responsive={responsive}
slideToIndex={currentIndex}
onSlideChanged={this.onSlideChanged}
/>
</Grid>
</div>
)
}
}
const mapStateToProps = (state) => ({
resume: state.resume,
});
export default connect(mapStateToProps, {getService }) (KitchenService);
//Error
TypeError: Cannot read property 'ItemsServices' of undefined
service API response
(console.log(services))
[
{
_id: "5f1971da18ba2b04704d65c2",
service_name: "Other",
service_image_url:
"https://res.cloudinary.com/tammycloudinary/image/upload/v1595503076/nou0knjbtkujxwjktang.png",
date: "2020-07-23T11:17:46.928Z",
__v: 0,
},
{
_id: "5f1971b218ba2b04704d65c1",
service_name: "Bedroom",
service_image_url:
"https://res.cloudinary.com/tammycloudinary/image/upload/v1595503036/kfiteeilh4doytio6gs8.png",
date: "2020-07-23T11:17:06.742Z",
__v: 0,
}
];
The issue is not coming from const items = this.galleryItems(); like I originally thought. It is coming from the constructor.
You are attempting to use the state object in order to build the initial state object. This obviously will not work.
constructor(props) {
super(props);
this.state = {
currentIndex: 0,
responsive: { 1024: { items: 3 } },
galleryItems: this.galleryItems(), // <-- Here is the problem
services : this.props.resume,
...props,
ItemsServices:[]
}
}
You attempt to initialize state by calling this.galleryItems. But that function relies on this.state already being declared. Since it has not been created yet (but is in the process of being declared), it is undefined and you get this error.
I don't think gallaryItems really belongs in state at all. It's generally not recommended to store JSX in state anyway. Instead just use the function like you have in the render to compute the JSX needed each render.
Another note: Don't use this.props in the constructor. Instead use the props that are passed in to the constructor.
Y0u can solve this with this solution as well with filter.
render() {
const { services, loading} = this.props.resume;
var checkImage = services.length === 0 ? [] : services.filter((item) => item.service_name === "Kitchen")
return(
<div>
<OwlCarousel className="owl-theme" loop margin={10} nav>
{checkImage.map((item, i) => (
<div className="col-xs-12 item" key={item._id} data-id={item._id} >
<img className="service-gallery-images" src={item.service_image_url} alt=""/>
</div>
))}
</OwlCarousel>
</div>
)
}
React newbie here, I am having problems with my TinySlider component. Each time I update in the UI how many posts can appear in the carousel, I get this error every other update which I need to fix:
Uncaught (in promise) TypeError: Cannot read property 'appendChild' of null
If I remove <TinySlider settings={...settings}></Tinyslider> I do not get this error.
I have tried this: { renderProfilesCarousel ? renderProfilesCarousel : '' } inside the <tinySlider> but that does not work.
Any idea what I could do here? Pretty stuck on this now.
// React
import * as React from 'react';
// Styling
import styles from './LinkedIn.module.scss';
// Importing the props
import { ILinkedInProps } from './ILinkedInProps';
// Importing the state
import { ILinkedInState } from './ILinkedInState';
// Removes special characters
import { escape } from '#microsoft/sp-lodash-subset';
// Library for making http requests
import axios from 'axios';
// Library for creating unique ids
import shortid from 'shortid';
// Fabric UI elements
import {
DocumentCard,
DocumentCardPreview,
DocumentCardType,
DocumentCardDetails,
DocumentCardTitle,
IDocumentCardPreviewProps
} from 'office-ui-fabric-react/lib/DocumentCard';
import { ImageFit, Image } from 'office-ui-fabric-react/lib/Image';
// Sort array
import sortBy from 'sort-array';
import TinySlider from "tiny-slider-react";
import { SPComponentLoader } from '#microsoft/sp-loader';
import "./styles.scss";
// LinkedIn Component Class
export default class LinkedIn extends React.Component<ILinkedInProps, ILinkedInState> {
// State needed for the component
constructor(props) {
super(props);
this.state = {
profiles: [],
isLoading: true,
errors: null
};
SPComponentLoader.loadCss('//cdnjs.cloudflare.com/ajax/libs/tiny-slider/2.9.2/tiny-slider.css');
}
// This function runs when component is first renderd
public componentDidMount() {
this.getProfiles();
}
// This function runs when props that have changed have been passed in
public componentDidUpdate(prevProps) {
if ( prevProps.listName !== this.props.listName || prevProps.postCount ! == this.props.postCount )
{
this.renderProfile();
}
}
// Grabs LinkedIn profiles - This service runs once a day
private getProfiles() {
let companyNameCreate: string;
let backUpImageCreate: string;
axios
.get(
"https://cors-anywhere-spfx.herokuapp.com/" +
"https://cache1.phantombooster.com/YRrbtT9qhg0/KJhwG7zo0zPE5zc9Eehn6Q/result.json"
)
.then(response => {
this.setState({
profiles: response.data.filter(d => d.postContent).map(post => {
if (post.profileUrl == 'https://www.linkedin.com/company/')
{
companyNameCreate = 'company';
backUpImageCreate = 'https://media-exp2.licdn.com/dms/image/C4D0BAQEbfV4VNvsJyg/company-logo_100_100/0?e=1587600000&v=beta&t=CX_s-ekYNn0TnXANeftQkLZ9jIvMW7PtDTLLcHcu9wY'
}
else if (post.profileUrl == 'https://www.linkedin.com/company/1')
{
companyNameCreate = 'company';
backUpImageCreate = 'https://media-exp2.licdn.com/dms/image/C4D0BAQG_Pr1cDaGfdA/company-logo_200_200/0?e=1587600000&v=beta&t=C0fWkjbO2Elth8K4pG4i_kzwlu8dvQvN1Ws-yKGxxP4'
}
else if (post.profileUrl == 'https://www.linkedin.com/company/2')
{
companyNameCreate = 'company';
backUpImageCreate = 'https://media-exp2.licdn.com/dms/image/C4D0BAQHdub-mnNwSNg/company-logo_100_100/0?e=1587600000&v=beta&t=druqo_O5gB5cExttREUlSdGnJhr4Wx2-PCjshJ0K0fI'
}
else if (post.profileUrl == 'https://www.linkedin.com/company/3')
{
companyNameCreate = 'company';
backUpImageCreate = 'https://media-exp2.licdn.com/dms/image/C4D0BAQEUKGn5i1EnQA/company-logo_100_100/0?e=1587600000&v=beta&t=uwE3CUaodiqmW2K3a3Hm57QDIDlMvrmfmoHDvlGnzuY'
}
else if (post.profileUrl =='https://www.linkedin.com/company/4')
{
companyNameCreate = 'company';
backUpImageCreate = 'https://media-exp2.licdn.com/dms/image/C4D0BAQGYqqxF43Rfdg/company-logo_200_200/0?e=1587600000&v=beta&t=4hmLzdbkjk_hL3rwonWgTbUF1V-itkyBEfLBh85G7_k'
}
else if (post.profileUrl == 'https://www.linkedin.com/company/5')
{
companyNameCreate = 'company';
backUpImageCreate = 'https://media-exp2.licdn.com/dms/image/C4E0BAQHsNKLawvW7zg/company-logo_100_100/0?e=1587600000&v=beta&t=26Otro4T3q90GznPxXX6n3oPTYYWIgzodOIask0enu4'
}
return {
...post,
companyName: companyNameCreate,
backUpImage: backUpImageCreate
}
})
});
})
// Error catching
.catch(errors => this.setState({ errors, isLoading: false }));
}
// Creates the renderd layout of the LinkedIn profile
private async renderProfile() {
let filter: string = '';
// Works out which profile to display
switch (this.props.listName) {
case "abfi":
filter = 'https://www.linkedin.com/company/1';
break;
case 'abEnzymes':
filter = 'https://www.linkedin.com/company/2';
break;
case 'abitec':
filter = 'https://www.linkedin.com/company/3';
break;
case 'ohly':
filter = 'https://www.linkedin.com/company/4';
break;
case 'pgpi':
filter = 'https://www.linkedin.com/company/5';
break;
case 'spiPharma':
filter = 'https://www.linkedin.com/company/6';
break;
case 'all':
filter = 'Post';
break;
default:
filter = 'https://www.linkedin.com/company/1';
return filter;
}
// Grabs the array of objects
let { profiles } = this.state;
const slotOrder = [
"", "1h","2h","3h","4h","5h","6h","7h","8h","9h","10h","11h","12h", "13h","14h","15h","16h","17h","18h","19h","20h","21h","22h", "23h", "2d", "3d", "4d", "5d", "6d", "1w", "2w", "3w", "1mo", "2mo", "3mo", "4mo", "5mo", "6mo", "7mo", "8mo", "9mo", "10mo", "11mo", "1yr", "2yr"
];
// Select only the needed objects from the array
let selectedProfile;
// Display all posts
if (this.props.listName !== 'all') {
selectedProfile = profiles.filter(profile => profile.profileUrl == filter);
} else {
selectedProfile = profiles.filter(profile => profile.action == filter);
}
selectedProfile = sortBy(selectedProfile, "postDate", { postDate: slotOrder })
selectedProfile = selectedProfile.splice(0, this.props.postCount)
// Renders the selected profile
let renderProfilesCarousel = selectedProfile.map(profile => {
// If LinkedIn post has no image, then add a fallback!
if (profile.imgUrl == "" || profile.imgUrl == null ) {
profile.imgUrl = profile.backUpImage;
}
// Removes hashtag line from posts
profile.postContent = profile.postContent.replace(/hashtag/g, '');
return(
<div className={styles.linkedInContainerCarousel} style={{ position: "relative" }} key={shortid.generate()}>
<a href={profile.postUrl} target="_blank" data-interception="off">
<DocumentCard
aria-label={profile.postContent}
className={styles.linkedInDocCard}
>
{ profile.imgUrl &&
<Image
src={profile.imgUrl}
imageFit={ImageFit.cover}
height={168}
/>
}
<DocumentCardTitle
title={profile.postContent}
shouldTruncate={true}
/>
<p className={ styles.linkedInCompany}>{profile.companyName}</p>
<p className={ styles.linkedInLikes}>{`Likes: ${profile.likeCount}`}</p>
</DocumentCard>
</a>
</div>
)
});
// Renders the selected profile
let renderProfiles = selectedProfile.map(profile => {
// If LinkedIn post has no image, then add a fallback!
if (profile.imgUrl == "" || profile.imgUrl == null ) {
profile.imgUrl = profile.backUpImage;
}
let previewProps: IDocumentCardPreviewProps = {
previewImages: [
{
name: profile.postContent,
previewImageSrc: profile.imgUrl,
iconSrc: null,
imageFit: ImageFit.cover,
height: 110,
width: 110
}
]
};
return(
<div className={styles.linkedInContainer} style={{ position: "relative" }} key={shortid.generate()}>
<a href={profile.postUrl} target="_blank" data-interception="off">
<DocumentCard
aria-label={profile.postContent}
className={styles.linkedInDocCard}
type={DocumentCardType.compact}
>
{ profile.imgUrl &&
<DocumentCardPreview {...previewProps} />
}
<DocumentCardDetails>
<DocumentCardTitle
title={profile.postContent}
shouldTruncate={true}
/>
<p className={ styles.linkedInCompany}>{profile.companyName}</p>
<p className={ styles.linkedInLikes}>{`Likes: ${profile.likeCount}`}</p>
</DocumentCardDetails>
</DocumentCard>
</a>
</div>
)
});
let settings: any;
if (this.props.toggleInfoHeaderValue == true )
{
settings = {
lazyload: true,
nav: false,
mouseDrag: false,
items: 1,
swipeAngle: false,
speed: 400,
autoplay: false,
axis: "horizontal",
autoHeight: false,
rewind: true,
fixedWidth: false
};
}
else
{
settings = {
lazyload: true,
nav: false,
mouseDrag: false,
items: 3,
swipeAngle: false,
speed: 400,
autoplay: false,
axis: "vertical",
autoHeight: false,
rewind: true,
fixedWidth: false
};
};
if (this.props.toggleInfoScrollValue) {
settings.autoplay = true;
} else {
settings.autoplay = false;
}
if (this.props.toggleInfoHeaderValue == true ) {
return(
<div>
<TinySlider settings={settings}>
{renderProfilesCarousel}
</TinySlider>
</div>
)
} else {
return (
<div className={styles.upArrows}>
<TinySlider settings={settings}>
{renderProfiles}
</TinySlider>
</div>
)
}
}
// Renders to the browser
public render(): React.ReactElement<ILinkedInProps> {
return (
<div className={ styles.linkedIn }>
<div className={ styles.container }>
<p className={ styles.title }>{escape(this.props.description)}</p>
<div>
{ this.renderProfile() }
</div>
</div>
</div>
);
}
}
Error in full:
Counld you try this instead
{ renderProfilesCarousel ? renderProfilesCarousel : <span></span> }
React likes it when it has elements, and I'm not sure how it'd deal with a ''
Edit to edit:
I think you'll want to move the actual JSX.Element out of the renderProfile() method. React doesn't take that as a child element.
So I added two new items to state (I guess you'll want three, one for renderProfilesCarousel too):
settings?: any;
renderProfiles?: JSX.Element[];
Then I did this at the bottom of the renderProfile() method:
/* if (this.props.toggleInfoHeaderValue == true) {
return (
<div>
<TinySlider settings={settings}>
{renderProfilesCarousel}
</TinySlider>
</div>
)
} else {
return (
<div /* className={styles.upArrows} >
<TinySlider settings={settings}>
{renderProfiles}
</TinySlider>
</div>
)
} */
console.log(renderProfiles.length);
this.setState({
settings: settings,
renderProfiles: renderProfiles,
isLoading: false
})
Then, in your return of the actual render to the browser is where I put the actual JSX.Element:
// Renders to the browser
public render(): React.ReactElement<ILinkedInProfilesProps> {
const {settings, renderProfiles} = this.state;
const theRenderProfileJsxElement: JSX.Element =
<div /* className={styles.upArrows} */>
<TinySlider settings={settings}>
{renderProfiles}
</TinySlider>
</div>;
return (
<div /* className={styles.linkedIn} */>
<div /* className={styles.container} */>
<p /* className={styles.title} */>{escape(this.props.description)}</p>
<div>
{this.state.isLoading === false &&
theRenderProfileJsxElement
}
</div>
</div>
</div>
);
}
And I used your state of isLoading to prevent the Carousel from loading prior to finishing all the logic and loading from above.
Also! If you don't have React Dev Tools on your browser, you need it!
I can see the component Carousel, but I didn't do the if logic for either the toggleInfoHeaderValue. Let's see if that works?
I have this simple react app, where I fetch the Flickr public feed. So, I can scroll to the end of the page and new content is going to show. So I would like to scroll until there is nothing else new, and the app stops trying to load more content, because it has reached the last item of the list, which is not happening if I try to scroll (you can see that on the loading message). How can I fix this?
Check the code below:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import $ from "jquery";
import PhotoListItem from "./photoListItem";
import "./photoApp.css";
export default class PhotoApp extends Component {
constructor(props) {
super(props);
this.state = {
photoList: [],
searchTerm: "cyanotype",
items: 8,
loadingState: false,
loadingMessage: ""
};
}
componentDidMount() {
this.getPhotoList();
this.onInfiniteScroll();
}
/* get data from Flickr public feed */
getPhotoList = () => {
const flickrApiPoint =
"https://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?&tags=" +
this.state.searchTerm;
try {
$.ajax({
url: flickrApiPoint,
dataType: "jsonp",
data: { format: "json" },
success: function(data) {
this.setState({ photoList: data.items });
}.bind(this)
});
} catch (err) {
console.log(err);
}
};
/* code for infinite scroll */
onInfiniteScroll = () => {
this.refs.iScroll.addEventListener("scroll", () => {
if (
this.refs.iScroll.scrollTop + this.refs.iScroll.clientHeight >=
this.refs.iScroll.scrollHeight - 20
) {
this.loadMoreItems();
}
});
};
/* code for infinite scroll */
loadMoreItems = () => {
if (this.state.loadingState) {
return;
}
this.setState({
loadingState: true,
loadingMessage: "Loading photos..."
});
setTimeout(() => {
this.setState(prevState => ({
items: prevState.items + 8,
loadingState: false,
loadingMessage: "No more photos to show."
}));
}, 1000);
};
render() {
console.log(this.state.photoList)
return (
<div className="appContainer" ref="iScroll">
<div className="appHeader">
<h1 className="headerTitle">
Welcome to Flickr Alternative Photography Feed!
</h1>
</div>
<div className="gridContainer">
{this.state.photoList
.slice(0, this.state.items)
.map((photo, index) => {
const author = photo.author.split(/"/)[1];
const authorLink = photo.description.split(/"/)[1];
const description = photo.description.split(/"/)[13];
return (
<PhotoListItem
key={index}
url={photo.media.m}
photoLink={photo.link}
title={photo.title}
author={author}
authorLink={authorLink}
description={description}
tags={photo.tags}
/>
);
})}
</div>
<React.Fragment>
{this.state.loadingState ? (
<p className="loading">{this.state.loadingMessage}</p>
) : (
<p className="loading">{this.state.loadingMessage}</p>
)}
</React.Fragment>
</div>
);
}
}
LIVE EXAMPLE HERE
Thank you!
You could check if the item that you've loaded exceeds your items in your ajax request
/* code for infinite scroll */
loadMoreItems = () => {
// hasMore = data.items.length (you may want to rename this more appropriately)
if (this.state.loadingState || (this.state.items > this.state.hasMore)) {
// Do not load if there's no more items
return;
}
...
Your onInfiniteScroll doesn't have any code right now that checks whether it should load more items, it just blindly does. So: at the end of getPhotoList you probably want to check whether that's the last page of results and if so, do a setState({ exhausted: true }) or something similar, so you can check that value in your onInfiniteScroll and not do anything if you see this.state.exhausted === true.
interface IRoleAddProps {
roles: Array<IRole>
}
interface IRoleAddState {
current: IRole | null
}
class RoleAdd extends React.Component<IRoleAddProps, IRoleAddState> {
state = {
current: null,
}
renderNoneSelect = () => {
return (
<div styleName="empty">
<SvgIcon name="arrow" styleName="icon-arrow" />
<span>Empty</span>
</div>
)
}
onRoleClick = (role: IRole) => {
this.setState({
current: role,
})
}
render() {
const { roles } = this.props
const current = this.state.current
return (
<div styleName="role-add">
<div styleName="role-list">
<div styleName="title">Select role:</div>
<div styleName="list">
{roles.map(role => {
const cls = classNames({
item: true,
active: current && ( current.id === role.id )
})
return (
<div
key={role.id}
styleName={cls}
className="g-text-inline"
onClick={this.onRoleClick.bind(this, role)}
>
<CheckBox />
<span>{role.name}</span>
</div>
)
})}
</div>
</div>
<div styleName="view">
{!current && this.renderNoneSelect()}
{current && 'view'}
</div>
</div>
)
}
}
export default RoleAdd
The code like this, but TS still tells me:
Even I tried:
And "!" also doesn't work
As you can see the "current" object can't be null because i have null check before i use it.
But typescript engine still show me that error.
I'm wondering is that because i initialized current object with null value, but ts can not figure out types from setState, so it takes current always null?
You'll need to assign a type to state, like
state: IRoleAddState = {
current: null
};
Then, state will be of type IRoleAddState and not { current: null }. After that, the methods you tried will work.
Explicitly defining the state in a constructor should solve the issue.
constructor(props) {
super(props);
this.state = {
current: null;
}
}
I'm follow the steps of this dependencie:
http://jossmac.github.io/react-images/
And it isn't work. No picture showing and there is showing an error message:
index.js:2178 Warning: Failed prop type: The prop onClose is marked
as required in Lightbox, but its value is undefined
Here is my code:
import React, { Component } from "react";
import Lightbox from "react-images";
const URL_INTERIORES = "http://localhost:3001/interiores";
const LIGHTBOX_IMAGE_SET = [
{
src: "/images/int_02.jpg",
caption: "A forest",
// As an array
srcSet: ["/images/int_02.jpg", "/images/int_02.jpg"]
},
{
src: "/images/int_02.jpg",
// As a string
srcSet: "/images/int_02.jpg 1024w, /images/int_02.jpg 800w, /images/int_02.jpg 500w, /images/int_02.jpg 320w"
}
];
class Interiores extends Component {
render() {
const { open } = this.state;
return (
<div>
<div>
<Lightbox
images={LIGHTBOX_IMAGE_SET}
isOpen={this.state.lightboxIsOpen}
onClickPrev={this.gotoPrevLightboxImage}
onClickNext={this.gotoNextLightboxImage}
onClose={this.closeLightbox}
/>
</div>
</div>
);
}
}
export default Interiores;
Does anybody know how to solve it? Tahnk you
Consider adding all the missing handlers & state in your class:
class Interiores extends Component {
state = {
lightboxIsOpen: false
}
gotoPrevLightboxImage() {
// Add the logic here
}
gotoNextLightboxImage() {
// Add the logic here
}
closeLightbox(e) {
// Add the logic here
}
render() {
const { lightboxIsOpen } = this.state;
return (
<div>
<Lightbox
images={LIGHTBOX_IMAGE_SET}
isOpen={lightboxIsOpen}
onClickPrev={() => this.gotoPrevLightboxImage()}
onClickNext={() => this.gotoNextLightboxImage()}
onClose={e => this.closeLightbox(e)}
/>
</div>
);
}
}