I am trying to build a reusable carousel that will have much different conditions.
So i need to be able to set this "imageQuery" on my display page, sending it as a string, and then in my carousel, render it as usable javascript
the query works if I just hard code it in, I am just trying to build upon it
My display page has this
const imageQuery = 'arts.fineartfields.finehome === "Yes"';
<MyCarousel
finearts={finearts}
imageQuery={imageQuery}
/>
my carousel page has this
export default function MyCarousel({ finearts, imageQuery }) {
const [index, setIndex] = useState(0);
const handleSelect = (selectedIndex, e) => {
setIndex(selectedIndex);
};
return (
<Carousel
activeIndex={index}
onSelect={handleSelect}
className="carousel-fade">
{finearts.nodes && finearts.nodes.map((arts) => (
{imageQuery} ?
<Carousel.Item className="" key={arts.databaseId}>
<Image src={arts.fineartfields.cloudlink}
alt={arts.featuredImage.node.altText}
className="carousel-image img-fluid shadow-sm"
width={arts.featuredImage.node.mediaDetails.width}
height={arts.featuredImage.node.mediaDetails.height}
/>
</Carousel.Item>
: null
), [])}
</Carousel>
)
}
You don't need to pass imageQuery props
<MyCarousel finearts={finearts} />
Carousel component
export default function MyCarousel({ finearts }) {
const [index, setIndex] = useState(0);
const handleSelect = (selectedIndex, e) => {
setIndex(selectedIndex);
};
return (
<Carousel
activeIndex={index}
onSelect={handleSelect}
className="carousel-fade">
{finearts.nodes && finearts.nodes.map((arts) => (
arts.fineartfields.finehome === "Yes" ? (
<Carousel.Item className="" key={arts.databaseId}>
<Image src={arts.fineartfields.cloudlink}
alt={arts.featuredImage.node.altText}
className="carousel-image img-fluid shadow-sm"
width={arts.featuredImage.node.mediaDetails.width}
height={arts.featuredImage.node.mediaDetails.height}
/>
</Carousel.Item>
) : null
), [])}
</Carousel>
)
}
Related
Hi all I have following code
const App = () => {
const mediaRef = useRef(null);
const navRef = useRef(null);
const [direction, setDirection] = useState(null);
const onChange = (currentSlide) => {
if (direction === "next") {
mediaRef.current.goTo(currentSlide + 1, false);
} else {
mediaRef.current.goTo(currentSlide - 1, false);
}
};
const handleNext = () => {
setDirection("next");
navRef.current.next();
};
const handlePrev = () => {
setDirection("prev");
navRef.current.prev();
};
const imageList = [ some images array ];
return (
<>
<>
<Carousel
asNavFor={navRef.current}
ref={mediaRef}
>
{imageList?.map((el, id) => (
<ImageWrapper key={id}>
<img src={el} alt={"name"} />
</ImageWrapper>
))}
</Carousel>
{imageList?.length > 1 && (
<>
<Button onClick={handlePrev}>
<LeftOutlined />
</Button>
<Button onClick={handleNext}>
<RightOutlined />
</Button>
</>
)}
</>
{imageList?.length > 1 && (
<Carousel
slidesToShow={3}
centerMode={true}
asNavFor={mediaRef.current}
ref={(carousel) => (navRef.current = carousel)}
beforeChange={onChange}
>
{imageList?.map((el, id) => (
<>
<divkey={id}>
<img src={el} alt={"name"} />
</div>
</>
))}
</Carousel>
)}
<>
<Button onClick={handlePrev}>
<LeftOutlined />
</Button>
<Button onClick={handleNext}>
<RightOutlined />
</Button>
</>
</>
);
};
I am doing following, I am taking antd carousel adding another carousel for thumbnails and putting custom arrows, clicking on next and on previouse buttons it automatically change main image and thumbnail.
Now I am trying to put onClick event on thumbnails, I mean Thumbnails should be clickable and by click, the large image and thumbnail should be changed. How can I achieve that ?
You can add a click handler on the thumbnail with the clicked id as parameter
<ThumbnailWrapper key={id}>
<img
src={el}
alt={"name"}
onClick={() => thumbnailClicked(id)}
/>
</ThumbnailWrapper>
then do something with the id in the defined function:
const thumbnailClicked = (id) => {
console.log("thumbnail clicked:",id);
//then e.g. set parent the same as the thumbnail.
mediaRef.current.goTo(id, false);
};
I have implemented a simple drag and drop code here below using react-beautiful-dnd. The frontend alone works perfectly fine, however, when I tried to connect this with the backend the items in the droppable context are unable to be dragged. That is, I am unable to drag the items within the column and also between columns. Further, I am unable to figure out how to pass the index of the elements in the mongoDb database.
The code I used is here below
projectsDashboard.js
function ProjectsDashboard() {
const handleDragEnd = ({destination, source}) => {
if (!destination) {
return
}
if (destination.index === source.index && destination.droppableId === source.droppableId) {
return
}
// Creating a copy of item before removing it from state
const itemCopy = {...state[source.droppableId].items[source.index]}
setState(prev => {
prev = {...prev}
// Remove from previous items array
prev[source.droppableId].items.splice(source.index, 1)
// Adding to new items array location
prev[destination.droppableId].items.splice(destination.index, 0, itemCopy)
return prev
})
}
const dispatch = useDispatch();
useEffect(() => {
dispatch(getStages());
},[dispatch]);
const { stage } = useSelector(state => state.stage);
var formattedArray = stage.map(item => Object.keys(item).map(i => item[i]));
console.log(formattedArray)
return (
<DragDropContext onDragEnd={handleDragEnd}>
{_.map(state, (data, key) => {
return(
<div key={key} className={"column"}>
{console.log(key , "KEY")}
<ProjectWrapper className="border">
<h3 className="title">{data.title}</h3>
</ProjectWrapper>
<Droppable droppableId={key}>
{(provided, snapshot) => {
return(
<div>
<div
ref={provided.innerRef}
{...provided.droppableProps}
className={"droppable-col"}
>
<hr className="line" style={{opacity: 10 }}></hr>
{stage.map(stages=>{
if(stages.status == key)
return(
<Draggable key={stages._id}
//index={index}
draggableId={stages._id} className="drag">
{(provided, snapshot) => {
console.log(snapshot)
return(
<div
className={`item ${snapshot.isDragging && "dragging"}`}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
{/* card name */}
<button className="stageDetails" style={{padding: "0",border: "none", background: "none"}}>
{stages.stageName}
</button>
<DeleteOutlinedIcon className="delete" />
</div>
)
}}
</Draggable>
)
})}
{provided.placeholder}
</div>
</div>
)
}}
</Droppable>
</div>
)
})}
</DragDropContext>
</div>
);
};
export default ProjectsDashboard;
I tried to toggle individual item but unfortunately whenever I try to toggle an item the other item gets affected. Here is my code:
const FAQ = () => {
const [open, setOpen] = useState(false);
const [data, setData] = useState(faqData);
return (
<FAQSection>
<FAQTitle>Frequently Asked Questions</FAQTitle>
<Questions>
<QuestionItemDetail>
{data.map((item) => {
const { id, question, answer } = item;
return (
<div key={id}>
<QuestionItem onClick={() => setOpen(!open)}>
<QuestionItemTitle>{question}</QuestionItemTitle>
{open ? <Close /> : <Add />}
</QuestionItem>
<ReadQuestion>
{open && (
<ReadQuestionDetail>
<ReadQuestionDesc>{answer}</ReadQuestionDesc>
</ReadQuestionDetail>
)}
</ReadQuestion>
</div>
);
})}
</QuestionItemDetail>
</Questions>
</FAQSection>
);
};
What might be wrong with this because I ensured the dummy data has a unique ID.
Because you use a boolean to control all open/close. You need to use index/id to control this.
const [open, setOpen] = useState(null);
...
onClick={() => setOpen(preOpen => preOpen === id ? null : id)}
...
{open === id && (<ReadQuestionDetail>...</ReadQuestionDetail>)}
Your open state is used for all of the items in your data array, which is why it affects all of the items when toggled.
I recommend:
putting all of the data item html/jsx inside a new component.
Inside this new component, create an open state like so:
const MyItemComponent = (id, question, answer) => {
const [open, setOpen] = useState(false);
return (
<div key={id}>
<QuestionItem onClick={() => setOpen(!open)}>
<QuestionItemTitle>{question}</QuestionItemTitle>
{open ? <Close /> : <Add />}
</QuestionItem>
<ReadQuestion>
{open && (
<ReadQuestionDetail>
<ReadQuestionDesc>{answer}</ReadQuestionDesc>
</ReadQuestionDetail>
)}
</ReadQuestion>
</div>
);
}
const FAQ = () => {
const [data, setData] = useState(faqData);
return (
<FAQSection>
<FAQTitle>Frequently Asked Questions</FAQTitle>
<Questions>
<QuestionItemDetail>
{data.map((item) => {
const { id, question, answer } = item;
return (
<MyItemComponent id={id} question={question} answer={answer} />
);
})}
</QuestionItemDetail>
</Questions>
</FAQSection>
);
};
This will give you an individual open state for each item.
See that loop loading two components. I would like to display only <Image /> by default, but when I click this element, I want it to turn into <YouTube /> (only the one I press, the others are still <Image />). I can do this on a class component, but I want to use a hook
export const MusicVideos = () => {
const [selectedVideo, setVideo] = useState(0);
return (
<Wrapper>
{videos.map(video => (
<div key={video.id}>
<Image src={video.image} hover={video.hover} alt="thumbnail" />
<YouTube link={video.link} />
</div>
))}
</Wrapper/>
);
};
you can bind onClick for your image and setVideo to video.id and compare with video.id to render image or video.
export const MusicVideos = () => {
const [selectedVideo, setVideo] = useState(0);
return (
<Wrapper>
{videos.map(video => (
{selectedVideo !== video.id ?
<Image onClick={() => setVideo(video.id) src={video.image} hover={video.hover} alt="thumbnail" /> :
<YouTube link={video.link} />
))}
</Wrapper/>
);
};
Create a component like this and pass it to the loop;
const YouTubeToggle = (video) => {
const [selectedVideo, setVideo] = useState(0);
return (
<div key={video.id}>
{selectedVideo == 0 &&
<Image src={video.image} onClick={() => setVideo(!selectedVideo)} hover={video.hover} alt="thumbnail" />
}
{selectedVideo != 0 &&
<YouTube link={video.link} />
}
</div>
);
}
export const MusicVideos = () => {
const [selectedVideo, setVideo] = useState(0);
return (
<Wrapper>
{videos.map(video => (
<YouTubeToggle video={video} />
))}
</Wrapper/>
);
};
I have a problem with my application. The component ExpansionPanel of Material-ui is opening more than one Panel. I need to open just one.
father.js
<div>
{props.listContratos.map((item, index) => {
if (item.ativo) {
return (
<PartesCardCollapse
listPartes={props.listPartes}
item={item}
key={index}
thunks={props.thunks}
hideSnackbar={props.hideSnackbar}
/>
);
}
})}
</div>
son.js
export default function PartesCardCollapse(props) {
const classes = useStyles();
const [expanded, setExpanded] = React.useState(false);
const handleChange = (expanded, panel) => (event, isExpanded) => {
setExpanded(isExpanded ? panel : false);
};
return (
<div className={classes.root} onClick={getListPartes}>
<ExpansionPanel
expanded={expanded === props.item.id}
onChange={handleChange(expanded, props.item.id)}
>