I am trying to create a Carousel of images and embedded Youtube videos (the first item is a youtube video and the rest are images)
I am using the React Responsive Carusel npm package but I can't find a way to create the carousel I want without bugs.
I saw a solution over here but it's only for videos.
Here is my code at the moment:
import React from 'react'
import 'react-responsive-carousel/lib/styles/carousel.min.css' // requires a loader
import { Carousel } from 'react-responsive-carousel'
import ReactPlayer from 'react-player'
const ModalImagesPreview = () => {
return (
<div>
<Carousel>
<div>
<ReactPlayer
url='https://www.youtube.com/watch?v=ysz5S6PUM-U'
volume='1'
muted
width='100%'
playing={true}
/>
</div>
<div>
<img src='https://cdn.dribbble.com/users/2146089/screenshots/12387473/media/bf9ffb522fe68ba57ebdc62bc3f16cc5.png' />
</div>
<div>
<img src='https://cdn.dribbble.com/users/427857/screenshots/12318706/media/f30f662dbf160022412812881b2afb43.jpg' />
</div>
</Carousel>
</div>
)
}
export default ModalImagesPreview
Thanks for the helpers!
Here is what I found on the react-responsive-carousel website
import 'react-responsive-carousel/lib/styles/carousel.min.css'; // requires a loader
import React from 'react';
import ReactPlayer from 'react-player';
import { Carousel } from 'react-responsive-carousel';
import { PropTypes } from 'prop-types';
import { Grid, makeStyles } from '#material-ui/core';
const DUMMY_VIDEOS = [
{
_id: '5fd025a181e2c80897c14ae1',
videoUrl: 'https://www.youtube.com/embed/AVn-Yjr7kDc'
}
];
const useStyles = makeStyles(theme => ({
carousel: {
margin: theme.spacing(2)
}
}));
const YoutubeSlide = ({ url, isSelected }) => (
<ReactPlayer width="100%" height="276px" url={url} playing={isSelected} />
);
const CarouselVideo = ({ data }) => {
const classes = useStyles();
const customRenderItem = (item, props) => (
<item.type {...item.props} {...props} />
);
const getVideoThumb = videoId =>`https://img.youtube.com/vi/${videoId}/default.jpg`;
const getVideoId = url =>url.substr('https://www.youtube.com/watch?v='.length, url.length);
const customRenderThumb = children =>
children.map(item => {
const videoId = getVideoId(item.props.url);
return <img key={videoId} src={getVideoThumb(videoId)} />;
});
return (
<Grid item md={6} xs={12}>
<Carousel
autoPlay={false}
className={classes.carousel}
emulateTouch={true}
showArrows={true}
showThumbs={true}
showStatus={false}
infiniteLoop={true}
renderItem={customRenderItem}
renderThumbs={customRenderThumb}
>
{data.map(v => (
<YoutubeSlide
url={v.videoUrl}
muted
playing={false}
key={v._id ? v._id : v.id}
/>
))}
</Carousel>
</Grid>
);
};
YoutubeSlide.propTypes = {
url: PropTypes.string,
isSelected: PropTypes.bool
};
CarouselVideo.propTypes = {
data: PropTypes.array
};
CarouselVideo.defaultProps = {
data: DUMMY_VIDEOS
};
export default CarouselVideo;
Last step is to call this CarouselVideo where you want to render with your data as props or just call it without passint anythind => this will display the dummy videos I added there.
So you can call it like the below:
// DisplayVideo.js file with default videos as shown below
const DisplayVideo = () => {
render( <CarouselVideo />)
}
// or with your data
const DisplayVideo = ({PASS_YOU_DATA_HERE}) => {
render( <CarouselVideo data={PASS_YOU_DATA_HERE} />)
}
Result:
(source: https://www.npmjs.com/package/react-responsive-carousel)
Related
By using console.log(responseData.places) I have checked the fetching works since I am using a hook for this and seems to work fine until I setLoadedPlaces with is the method I use to update the loadedPlaces which I later use to get the values to fill the frontend part of the website.
This is the output I get from this console.log I did and the values are correct.
[{…}]
0: address: "sis se puede
busrespect: 'tu puedes',
creator: "6384e2f543f63be1c560effa"
description: "al mundial"
id: "6384e30243f63be1c560f000"
image:"https://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Empire_State_Building_%28aerial_view%29.jpg/400px-Empire_State_Building_%28aerial_view%29.jpg"location: {lat: -12.086158, lng: -76.898019}
title: "Peru"
__v: 0
_id: "6384e30243f63be1c560f000"[[Prototype]]:
Objectlength: 1[[Prototype]]: Array(0)
So after this this the code I have in the frontend (SINCE the backend works properly) Let me know if you have any doubts with this logic
This is UserPlaces.js
import React, {useState, useEffect } from 'react';
import PlaceList from '../components/PlaceList';
import { useParams } from 'react-router-dom';
import { useHttpClient } from '../../shared/hooks/http-hook';
import ErrorModal from '../../shared/components/UIElements/ErrorModal';
import LoadingSpinner from '../../shared/components/UIElements/LoadingSpinner';
const UserPlaces = () => {
const {loadedPlaces, setLoadedPlaces} = useState();
const {isLoading, error, sendRequest, clearError } = useHttpClient();
const userId = useParams().userId;
useEffect(() => {
const fetchPlaces = async () => {
try {
const responseData = await sendRequest(
`http://localhost:5000/api/places/user/${userId}`
);
console.log(responseData.bus_stops)
setLoadedPlaces(responseData.bus_stops);
} catch (err) {}
};
fetchPlaces();
}, [sendRequest, userId]);
return (
<React.Fragment>
<ErrorModal error={error} onClear={clearError} />
{isLoading && (
<div className="center">
<LoadingSpinner />
</div>
)}
{!isLoading && loadedPlaces && <PlaceList items={loadedPlaces} />}
</React.Fragment>
);
};
export default UserPlaces;
This is Place-List.js
import React from 'react';
import "./PlaceList.css"
import Card from '../../shared/components/UIElements/Card'
import PlaceItem from './PlaceItem';
import Button from '../../shared/components/FormElements/Button';
const PlaceList = props => {
if (props.items.length === 0) {
return (
<div className='place-list-center'>
<Card>
<h2>No bus stops available. Be the first one to create one!</h2>
<Button to='/places/new'> Create Bus Stop </Button>
</Card>
</div>
);
}
return (
<ul className="place-list">
{props.items.map(bus_stops => (
<PlaceItem
key={bus_stops.id}
id={bus_stops.id}
image={bus_stops.image}
title={bus_stops.title}
busrespect={bus_stops.busrespect}
description={bus_stops.description}
address={bus_stops.address}
creatorId={bus_stops.creator}
coordinates={bus_stops.location}
/>
))}
</ul>
);
};
export default PlaceList;
This is PlaceItem.js
import React, { useState } from 'react';
import { useContext } from 'react';
import Card from '../../shared/components/UIElements/Card';
import Button from '../../shared/components/FormElements/Button';
import Modal from '../../shared/components/UIElements/Modal';
import Map from '../../shared/components/UIElements/Map';
import {AuthContext} from '../../shared//context/auth-context'
import "./PlaceItem.css";
const PlaceItem = props => {
const auth = useContext(AuthContext);
const [showMap, setShowMap] = useState(false);
const [showConfirmModal, setShowConfirmModal] = useState(false);
const openMapHandler = () => setShowMap(true);
const closeMapHandler = () => setShowMap(false);
const showDeleteWarningHandler = () => {
setShowConfirmModal(true);
};
const cancelDeleteHandler = () => {
setShowConfirmModal(false);
};
const confirmDeleteHandler = () => {
setShowConfirmModal(false); //when clicked close the new Modal
console.log('DELETING...');
};
return (
<React.Fragment>
<Modal show={showMap}
onCancel={closeMapHandler}
header={props.address}
contentClass="place-item__modal-content"
footerClass="place-item__modal-actions"
footer={<Button onClick={closeMapHandler}>Close </Button>}
>
<div className='map-container'>
<Map center={props.coordinates} zoom={16}/> {/* Should be props.coordinates but we writing default data for now until geocoding solved. */}
</div>
</Modal>
<Modal
show={showConfirmModal}
onCancel={cancelDeleteHandler}
header="Are you entirely sure?"
footerClass="place-item__modal-actions"
footer={
<React.Fragment>
<Button inverse onClick={cancelDeleteHandler}>
CANCEL
</Button>
<Button danger onClick={confirmDeleteHandler}>
DELETE
</Button>
</React.Fragment>
}
>
<p>
Do you want to proceed and delete this place? Please note that it
can't be undone thereafter.
</p>
</Modal>
<li className='"place=item'>
<Card className="place-item__content">
<div className='place-item__image'>
<img src={props.image} alt={props.title}/>
</div>
<div className='place-item__info'>
<h2>{props.title}</h2>
<h3>{props.address}</h3>
<p>{props.description}</p>
<p>{props.busrespect}</p>
</div>
<div className='place-item__actions'>
<Button inverse onClick={openMapHandler}> VIEW ON MAP</Button>
{auth.isLoggedIn && (<Button to={`/places/${props.id}`}> EDIT</Button> )}
{auth.isLoggedIn &&<Button danger onClick={showDeleteWarningHandler}> DELETE </Button>}
</div>
</Card>
</li>
</React.Fragment>
);
};
export default PlaceItem;
This is auth-context:
import { createContext } from "react";
export const AuthContext = createContext({
isLoggedIn: false,
userId: null,
login: () => {},
logout: () => {}});
This is is Modal.js
import React from 'react';
import ReactDOM from 'react-dom';
import Backdrop from './Backdrop';
import { CSSTransition } from 'react-transition-group';
import './Modal.css';
const ModalOverlay = props => {
const content =(
<div className={`modal ${props.className}`} style = {props.style}>
<header className={`modal__header ${props.headerClass}`}>
<h2>{props.header}</h2>
</header>
<form
onSubmit={
props.onSubmit ? props.onSubmit : event => event.preventDefault()
}
>
<div className={`modal__content ${props.contentClass}`}>
{props.children}
</div>
<footer className={`modal__content ${props.footerClass}`}>
{props.footer}
</footer>
</form>
</div>
);
return ReactDOM.createPortal(content, document.getElementById('modal-hook'));
};
const Modal = props => {
return (
<React.Fragment>
{props.show && <Backdrop onClick={props.onCancel} />}
<CSSTransition in={props.show}
mountOnEnter
unmountOnExit
timeout={200}
classNames="modal"
>
<ModalOverlay {...props}/>
</CSSTransition>
</React.Fragment>
);
};
export default Modal;
Also Trust the routing is correct since I have checked it already and I am just wondering if the logic in REACT with loadedPlaces, PlaceItema and PlaceList makes sense and it working. Let me know please. It will be really helpful.
Summary: Not getting any error but no visual data appears in the scren just the header of my website and the background (rest is empty) even though logic is functional.
const {loadedPlaces, setLoadedPlaces} = useState();
change the above line to
const [loadedPlaces, setLoadedPlaces] = useState();
I'm trying to learn about APIs and trying to code a REACT app to go along with it. I am sure the issue is a minor one, but I can't seem to crack it.
The relevant code is pasted below, the API is fetched in index.js.
The contents of the API is printed to the console without issue but I can not seem to get it right when going through my list and event details.
I am new to coding so I would appreciate any feedback given.
App.js
import React, { useState, useEffect } from "react";
import { CssBaseline, Grid } from "#material-ui/core";
import { getEventsData } from "./api";
import Header from "./components/Header/Header";
import List from "./components/List/List";
import EventDetails from "./components/EventDetails/EventDetails";
const App = () => {
const [events, setEvents] = useState([]);
useEffect(() => {
getEventsData()
.then((data) => {
console.log(data);
console.log(Array.isArray(data))
setEvents(data);
})
}, []);
return (
<>
<CssBaseline />
<Header />
<List EventDetails={EventDetails} />
</>
)
}
export default App;
index.js
import axios from "axios";
const URL = 'https://api-football-v1.p.rapidapi.com/v3/fixtures'
const options = {
params: {date: '2022-02-12', league: '39', season: '2021'},
headers: {
'x-rapidapi-host': 'api-football-v1.p.rapidapi.com',
'x-rapidapi-key': xxxXXXxxxXXXxxx'
}
};
export const getEventsData = async () => {
try {
const { data } = await axios.get(URL, options);
// Kan det ha något med options att göra? https://stackoverflow.com/questions/68367352/multiple-url-variable-async-await-axios
return data;
} catch (error) {
}
};
List.jsx
import React, { useState } from "react";
import { CircularProgress, Grid, Typography, InputLabel, MenuItem, FormControl, Select, ButtonGroup, Button } from "#material-ui/core";
import EventDetails from "../EventDetails/EventDetails"
import useStyles from "./styles"
const List = ({ events }) => {
const classes = useStyles();
const [type, setType] = useState("premierleague");
return (
<div className={classes.container}>
<FormControl className={classes.formControl}>
<InputLabel>Sport</InputLabel>
<Select value={type} onChange={(e) => setType(e.target.value)}>
<MenuItem value="premierleague">Premier League</MenuItem>
<MenuItem value="formula1">Formula 1</MenuItem>
</Select>
{/*<ButtonGroup value={type} onClick={(e) => setType(e.target.value)}>
<Button value="premierleague">Premier League</Button>
<Button value="formula1">Formula 1</Button>
</ButtonGroup>*/}
</FormControl>
<Grid container spacing={3} className={classes.list}>
{events?.map((event, i) => (
<Grid item key={i} xs={12}>
<EventDetails event={event} />
</Grid>
))}
</Grid>
</div>
)
}
export default List;
EventDetails.jsx
import React from "react";
const EventDetails = ({ event }) => {
console.log(event)
return (
<h3>{event.league}</h3>
)
}
export default EventDetails;
You're not sending the events to List component.
Try changing in App.js:
return (
<>
<CssBaseline />
<Header />
<List events={events} />
</>
)
I want to integrate a search functionality in my Next.js app which should look like this:
User types a keyword in searchBar which is inside of Header
After clicking on the search button the keyword should be passed on the SearchResult page, in which I load it dynamically into the youtube-search-api link
The structure looks like this:
Header.js (contains SearchBar component)
_app.js (contains Header and components)
SearchResults.js (inside pages folder, should fetch typed keyword from Header)
I tried it with zustand and it looks like this currently:
Header.js:
import SearchBar from "./SearchBar";
const Header = () => {
return (
<div className={styles.header}>
...
<SearchBar />
...
</div>
);
};
export default Header;
SearchBar.js:
import create from 'zustand';
import { useRouter } from 'next/router';
import Image from 'next/image';
import styles from '../styles/Header.module.scss';
import loupe from '../public/images/loupe.png';
const useStore = create((set) => ({
keyword: '',
setKeyword: (keyword) =>
set((state) => ({
...state,
keyword,
})),
}));
const SearchBar = () => {
const router = useRouter();
const keyword = useStore((state) => state.keyword);
const setKeyword = useStore((state) => state.setKeyword);
const handleClick = (e) => {
e.preventDefault();
router.push('/searchResults');
};
return (
<div className={styles.searchBar}>
<input
type='text'
value={keyword}
placeholder='Suche...'
onChange={(e) => setKeyword(e.target.value)}
/>
<button className={styles.searchBtn} type='submit' onClick={handleClick}>
<Image src={loupe} alt='' />
</button>
</div>
);
};
export default SearchBar;
_app.js:
import Header from '../components/Header';
function MyApp({ Component, pageProps }) {
return (
<>
<Header />
<Component {...pageProps} />
</>
);
}
export default MyApp;
and SearchResults.js:
import { fetchData } from '../lib/utils';
import Moment from 'react-moment';
import { Modal } from 'react-responsive-modal';
import ReactPlayer from 'react-player/youtube';
export default function SearchResults({ videos }) {
console.log(videos);
const [modalIsOpen, setModalIsOpen] = useState(false);
const [modalData, setModalData] = useState(null);
const videoURL = 'https://www.youtube.com/watch?v=' + modalData;
const sortedVids = videos
.sort((a, b) =>
Number(
new Date(b.snippet.videoPublishedAt) -
Number(new Date(a.snippet.videoPublishedAt))
)
)
.filter((vid) => vid.snippet.title.toLowerCase());
return (
<>
<div className={`${styles.playlist_container} ${styles.search}`}>
<div className={styles.main_container}>
<h1>Search results</h1>
{sortedVids
.filter((v) => v.snippet.title !== 'Private video')
.map((vid, id) => {
return (
<div className={styles.item_container}
key={id}>
<div className={styles.clip_container}>
<Image
className={styles.thumbnails}
src={vid.snippet.thumbnails.medium.url}
layout='fill'
objectFit='cover'
alt={vid.snippet.title}
/>
<button
className={styles.playBtn}
onClick={() => {
setModalData(vid.snippet.resourceId.videoId);
console.log(modalData);
setModalIsOpen(true);
}}
>
<Image src='/images/play.svg' width='60' height='60' />
</button>
</div>
<div className={styles.details_container}>
<h3>{vid.snippet.title}</h3>
</div>
</div>
);
})}
</div>
</div>
<div>
<Modal
open={modalIsOpen}
onClose={() => setModalIsOpen(false)}
center
classNames={{
overlay: 'customOverlay',
modal: 'customModal',
overlayAnimationIn: 'customEnterOverlayAnimation',
overlayAnimationOut: 'customLeaveOverlayAnimation',
modalAnimationIn: 'customEnterModalAnimation',
modalAnimationOut: 'customLeaveModalAnimation',
}}
animationDuration={800}
>
<ReactPlayer
playing={true}
url={videoURL}
width='100%'
height='calc(100vh - 100px)'
config={{
youtube: {
playerVars: {
autoplay: 1,
controls: 1,
},
},
}}
/>
</Modal>
</div>
<Footer />
</>
);
}
export async function getStaticProps() {
const keyword = useStore((state) => state.keyword);
const { YOUTUBE_KEY } = process.env;
const uploadsURL = `https://youtube.googleapis.com/youtube/v3/search?part=snippet&channelId=UCbqKKcML7P4b4BDhaqdh_DA&maxResults=50&key=${YOUTUBE_KEY}&q=${keyword}`;
async function getData() {
const uploadsData = fetchData(uploadsURL);
return {
videos: await uploadsData,
};
}
const { videos } = await getData();
return {
revalidate: 86400,
props: {
videos: videos.items,
},
};
}
Would someone please help me out by telling me what I did wrong and how it works in the right way? Thank you guys!!
I have a post page in blog model, which includes Detail and Comment Component. getStaticProps from the post page gets the data, and I am passing this data as props to the Detail Component. Yet the the Detail component is not getting rendered.
Here's the post page:
import BlogDetail from "../../components/BlogDetail/BlogDetail"
import { CSSTransition } from 'react-transition-group'
import AuthContextProvider from "../../context/AuthContext"
import Cookie from "../../components/Cookie"
import { ThemeContext } from "../../context/ThemeContext"
import { useContext } from "react"
import '#fortawesome/fontawesome-svg-core/styles.css'
import dynamic from 'next/dynamic'
const Navbar = dynamic(() => import("../../components/Navbar"), { ssr: false })
import axios from "axios"
import { baseURL } from "../../functions/baseUrl"
export const getStaticPaths = async () => {
const res = await axios.get(baseURL + "/post/");
const info = await res.data
const paths = info.map(datum => {
return {
params: { slug: datum.slug }
}
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const slug = context.params.slug;
const res = await axios.get(baseURL + '/post/' + slug + "/");
const data = await res.data;
return {
props: { datum: data }
}
}
const Blog = (datum) => {
const [dark] = useContext(ThemeContext)
return (
<div className={`main ${dark}`}>
<AuthContextProvider>
<Navbar />
<CSSTransition
in={true}
classNames="pagetransitions"
timeout={100}
key={1}
appear={true}
unmountOnExit
>
<div>
<Cookie />
<BlogDetail title={datum.title} datum={datum} />
</div>
</CSSTransition>
</AuthContextProvider>
</div>
)
}
export default Blog;
And my BlogDetail model:
import React, { useState } from 'react';
import styles from "../../styles/blogDetail.module.css"
import timeformatter from "../../functions/timeFormatter"
import Tags from "../Tags";
import Head from "next/head"
import dynamic from 'next/dynamic'
const Favourite = dynamic(() => import("./Favourite"), { ssr: false })
const Comment = dynamic(() => import("./Comment"), { ssr: false })
function BlogDetail(props) {
const data = useState(props.datum)
function createMarkup() {
return { __html: data.text };
}
return (
<div className={styles.blog_text_container}>
<div>
<h1>{data.title}</h1>
<Tags tag={data.tags} />
{data.image_head === null ? (
<span></span>
) : (
<div className={styles.article_detail_image}>
<img className={styles.blog_header_image_detail} alt={data.alt_image_text} src={data.image_head}></img>
</div>
)}
<br></br>
<div dangerouslySetInnerHTML={createMarkup()} />
<br></br>
<span>{data.comments}</span>
<br></br>
<span>Published: {timeformatter(data.created_at)}</span>
<br></br><br></br>
<Favourite id={data.id} favcount={data.favcount} /><br></br>
<Comment id={data.id} /><br></br>
<br></br>
</div>
</div>
)
}
export default BlogDetail
I have tried passing my props individually like the titles, texts. But nodda. I have tried directly rendering the props without including state. Any help would appreciated.
In post page destructure dataum
...other code remains same
const Blog = ({datum}) => {
...other code remains same
In blogdetail page
...other code remains same
function BlogDetail({datum : data}) { // destructuring dataum and naming it as data since you have used data.* in your code
// you donot need useState here
...other code remains same
The issue is probably here
// some code
const Blog = (datum) => {
// some code
Make it to
const Blog = ({datum}) => {
// your code
As explained here
https://nextjs.org/docs/basic-features/data-fetching#simple-example
I am developing a front end application using react hooks where I need to upload one/multiple images.
Then i need to implement two features on the uploaded images (shown as bootstrap grid)
1.Drag/click to select one/multiple images (I am using react-selecto library for this)
2.Drag and change the order of the selected images (I and using react-dnd for this)
The problem here is:
1.When I use react-dnd alone it works absolutely fine.
2.When I use both react-selecto and react-dnd, then react-dnd no more works. Only react-selecto works.
To get a more clearer picture, when both the libraries are used together, user can select one/more images by clicking/dragging but after that when user tries to change the order by dragging selected images,nothing happens (no mouse response) and images cannot be moved from its position.
Thanks in advance. Need help.
The code is here:
App.js
import React, { useState, useEffect } from "react";
import "./App.css";
import { DndProvider } from "react-dnd";
import {HTML5Backend} from "react-dnd-html5-backend";
import UploadForm from "./upload";
import Images from "./images";
const App = () => {
const [data, setData] = useState([]);
const addImages = (images, description) => {
let t = {
images: images,
description: description,
};
setData((data) => data.concat(t));
};
useEffect(() => {
console.log("useState", data);
}, [data]);
return (
<div>
<UploadForm onSubmit={addImages} />
<DndProvider backend={HTML5Backend}>
<Images imgData={data}/>
</DndProvider>
</div>
);
};
export default App;
images.js
import React, { useEffect, useState, useRef } from "react";
import "../node_modules/bootstrap/dist/css/bootstrap.min.css";
import Image from "./image";
import update from "immutability-helper";
import Selecto from "react-selecto";
const Images = ({ imgData }) => {
const [images, setImages] = useState([]);
useEffect(() => {
let temp = [];
imgData.forEach((item) => {
item.images.forEach((image) => {
let t = {
key: image.text,
photo: image,
description: item.description,
};
temp.push(t);
});
});
setImages(temp);
}, [imgData]);
useEffect(() => {
console.log(images);
}, [images]);
const moveImage = (dragIndex, hoverIndex) => {
const draggedImage = images[dragIndex];
setImages(
update(images, {
$splice: [
[dragIndex, 1],
[hoverIndex, 0, draggedImage],
],
})
);
};
const imgList = images.map((img, index) => (
<Image image={img} moveImage={moveImage} index={index}/>
));
return (
<div className="container p-5 elements selecto-area">
<Selecto
dragContainer={".elements"}
selectableTargets={[".imageCube"]}
hitRate={100}
selectByClick={true}
selectFromInside={false}
toggleContinueSelect={["shift"]}
onSelect={(e) => {
e.added.forEach((el) => {
el.classList.add("selected");
console.log(el);
});
e.removed.forEach((el) => {
el.classList.remove("selected");
});
}}
></Selecto>
<div className="row">{imgList}</div>
</div>
);
};
export default Images;
image.js
import React, { useRef } from "react";
import { useDrag, useDrop } from "react-dnd";
import "../node_modules/bootstrap/dist/css/bootstrap.min.css";
const type = "Image";
const Image = ( { image, moveImage, index } ) => {
const ref = useRef(null);
const [{ isDragging }, drag] = useDrag({
item: { type, id: image.id, index },
collect: monitor => ({
isDragging: monitor.isDragging()
})
});
const [, drop] = useDrop({
accept: type,
hover(item) {
if (!ref.current) {
return;
}
const dragIndex = item.index;
const hoverIndex = index;
if (dragIndex === hoverIndex) {
return;
}
moveImage(dragIndex, hoverIndex);
item.index = hoverIndex;
}
});
drag(drop(ref));
console.log(ref);
return(
<div className="col-sm-3 mt-3">
<div className="hvrbox imageCube" ref={ref} style={{ opacity: isDragging ? 0.7 : 1 }}>
<div className="card">
<div className="card-header">
<img src={image.photo.preview} alt="" width="210" height="150"/>
<div className="mt-1 text-center">
<strong>{image.photo.text}</strong>
</div>
</div>
</div>
<div className="hvrbox-layer_top hvrbox-layer_scale">
<div className="hvrbox-text">
{image.description ? image.description : image.photo.text}
</div>
</div>
</div>
</div>
);
};
export default Image;
Thanks in advance. Need help.