I have a problem, where I need to fetch data when user scrolls to the bottom of the page. To solve this problem I use intersection Observer. And it works in Chrome, Firefox, Opera and Safari, but it doesn't work in Edge for a reason that I don't understand (and there is no error as well).
Here is what it is supposed to be
And here is Edge (no Loading...)
I put console.log inside handleObserver function (inside if (this.state.prevY > y) {} statement) --> in Edge it didn't trigger
And I've tried to reference the target by id instead of this.loadingRef - the result was the same.
Here is my react component:
/**
* App main react component
*/
export default class Main extends Component {
state = {
cards: [],
isFetching: false,
page: 1,
prevY: 0,
sortValue: 'name',
searchValue: '',
prevSearchValue: '',
numberLoaded: null,
};
/**
* Initial data fetch
*/
componentDidMount() {
this.getCards(this.state.page);
// Options
const options = {
root: null, // Page as root
rootMargin: '0px',
threshold: 1.0,
};
// Create an observer
this.observer = new IntersectionObserver(
this.handleObserver.bind(this), // callback
options
);
// Observe the `loadingRef`
this.observer.observe(this.loadingRef);
}
/**
* Callback for Intersection Observer
*/
handleObserver(entities, observer) {
const y = entities[0].boundingClientRect.y;
if (this.state.prevY > y) {
const curPage = this.state.page + 1;
this.getCards(curPage, this.state.sortValue, this.state.searchValue);
this.setState({page: curPage});
}
this.setState({prevY: y});
}
/**
* Data fetch
*/
getCards(page, sortValue = 'name', searchValue = '') {
//... code
}
/**
* Renders component
*/
render() {
const loadingCSS = {
height: '10px',
marginTop: '0',
width: '1px',
};
const {cards, isFetching, numberLoaded} = this.state;
return (
<main className="l-main">
<h1 className="t1">
MTG Creatures{numberLoaded && ` (${numberLoaded} loaded)`}
</h1>
{!isFetching && cards.length === 0 && (
<p className="t0">No cards have been found</p>
)}
{/* code */}
{cards.length !== 0 && <Cards cards={cards} />}
<div
ref={(loadingRef) => (this.loadingRef = loadingRef)}
style={loadingCSS}
>
{isFetching && <Loader />}
</div>
</main>
);
}
}
Per suggestion in MS Edge: IntersectionObserver. Does it work for you? I've tried to add min-width, min-height and a border --> it didn't work for me
Related
I have a button on the site and a ToolTip to it, which describes the action of the button.
But there is one bug that I can not solve (and I'm already starting to doubt if there is a solution to this problem).
Description of the problem: when the user hovers over the icon, a tooltip appears - everything works fine here. But if at this moment the table is scrolling, then the tooltip flies out of bounds. It's hard to describe, take a look
Pay attention to how the tooltip (if the cursor is hovered over) flies up or down when scrolling.
Tell me how to solve this problem?
<div>
<Tooltip
title="Delete"
arrow
componentsProps={{
tooltip: {
sx: {
bgcolor: '#a3a3a3',
'& .MuiTooltip-arrow': {
color: '#a3a3a3',
},
},
},
}}
PopperProps={{
modifiers: [
{
name: "offset",
options: {
offset: [0, -8],
},
},
],
}}>
<DeleteForeverIcon/>
</Tooltip>
</div>
Instruction: hover over any cell from the first column, wait for the tooltip to appear. Then scroll the wheel up or down and see how the tooltip goes outside the table
P.s. Please note that this question has already been answered. And in principle this solution is working. But I had a lot of problems when adding this solution to my real code. Probably a simple solution for me here would be to simply cancel the scrolling when you hover over the button. Tell me how this can be done (but keep in mind that position: fixed is not suitable in this case)
My approach is different, where each tooltip maintains its own state. It is using IntersectionObserver to determine if the ToolTip component is viewable. When the component is no longer viewable, it will hide the Popper (the tooltip popup) by setting the CSS to display: 'none' via the sx prop on PopperProps.
Codesandbox Example: Here
Here is the modified file FileDownloadButton.jsx:
import React from "react";
import FileDownloadIcon from "#mui/icons-material/FileDownload";
import { ButtonGroup, Tooltip } from "#mui/material";
export default function FileDownloadButton() {
const tipRef = React.useRef(null);
const [inView, setInView] = React.useState(false);
const cb = (entries) => {
const [entry] = entries;
entry.isIntersecting ? setInView(true) : setInView(false);
};
React.useEffect(() => {
const options = {
root: null,
rootMargin: "0px"
};
const ref = tipRef.current;
const observer = new IntersectionObserver(cb, options);
if (ref) observer.observe(ref);
return () => {
if (ref) observer.unobserve(ref);
};
}, [tipRef]);
return (
<ButtonGroup>
<div>
<Tooltip
ref={tipRef}
title="Download record "
arrow
componentsProps={{
tooltip: {
sx: {
bgcolor: "#a3a3a3",
"& .MuiTooltip-arrow": {
color: "#a3a3a3"
}
}
}
}}
PopperProps={{
sx: { display: inView ? "block" : "none" },
modifiers: [
{
name: "offset",
options: {
offset: [0, -8]
}
}
]
}}
>
<FileDownloadIcon />
</Tooltip>
</div>
</ButtonGroup>
);
}
Changes for reference
Change 1
export default function FileDownloadButton() {
const tipRef = React.useRef(null);
const [inView, setInView] = React.useState(false);
const cb = (entries) => {
const [entry] = entries;
entry.isIntersecting ? setInView(true) : setInView(false);
};
React.useEffect(() => {
const options = {
root: null,
rootMargin: "0px"
};
const ref = tipRef.current;
const observer = new IntersectionObserver(cb, options);
if (ref) observer.observe(ref);
return () => {
if (ref) observer.unobserve(ref);
};
}, [tipRef]);
Change 2
PopperProps={{
sx: { display: inView ? "block" : "none" },
Update 1
Original poster wants toggle
Codesandbox example
import React, { useState } from "react";
import FileDownloadIcon from "#mui/icons-material/FileDownload";
import { ButtonGroup, IconButton, Tooltip } from "#mui/material";
import VisibilityOffIcon from "#mui/icons-material/VisibilityOff";
import VisibilityIcon from "#mui/icons-material/Visibility";
export default function FileDownloadButton() {
const [click, setClick] = useState(true);
const tipRef = React.useRef(null);
const [inView, setInView] = React.useState(false);
const cb = (entries) => {
const [entry] = entries;
entry.isIntersecting ? setInView(true) : setInView(false);
};
React.useEffect(() => {
const options = {
root: null,
rootMargin: "0px"
};
const ref = tipRef.current;
const observer = new IntersectionObserver(cb, options);
if (ref) observer.observe(ref);
return () => {
if (ref) observer.unobserve(ref);
};
}, [tipRef]);
return (
<ButtonGroup>
<div>
<Tooltip
ref={tipRef}
title={click ? "Show item" : "Hide Item"}
arrow
componentsProps={{
tooltip: {
sx: {
bgcolor: "#a3a3a3",
"& .MuiTooltip-arrow": {
color: "#a3a3a3"
}
}
}
}}
PopperProps={{
sx: { display: inView ? "block" : "none" },
modifiers: [
{
name: "offset",
options: {
offset: [0, -8]
}
}
]
}}
>
<IconButton onClick={() => setClick(!click)}>
{click ? <VisibilityOffIcon /> : <VisibilityIcon />}
</IconButton>
</Tooltip>
</div>
</ButtonGroup>
);
}
I think this is browser specific issue. When I checked the given url( https://codesandbox.io/s/silly-grass-1lb3qw) in firefox browser it was working fine(but not in the chrome). Later figured that out hover while scrolling on element will work differently in the chrome compare to other browsers since latest versions.
I made following changes to make it work in chrome. Basically whenever we hover any item then the material tooltip is being added to the document. So what I did was I have attached an scroll event and if there is any material tooltip element is present I just simply removed it.
DeviceTable.jsx
export default function DevicesTable() {
const tableRef = useRef();
function removeElementsByClass(className){
const elements = document.getElementsByClassName(className);
while(elements.length > 0){
elements[0].remove();
}
}
useEffect(() => {
if (tableRef.current) {
tableRef.current.addEventListener("scroll", (e) => {
// CLASS NAME OF THE TOOLTIP ATTACHED TO THE DOM. THERE ARE MULTIPLE CLASSES BUT I FOUND FOLLOWING CLASSNAME TO BE UNIQUE. PLEASE CROSS CHECK FROM YOUR END AS WELL.
//YOU CAN CHECK THIS BY PASSING open={true} attribute on <Tooltip> AND INSPECT DOM
removeElementsByClass("css-yk351k-MuiTooltip-tooltip")
});
}
return () => {
if(tableRef.current) {
tableRef.current.removeEventListener("scroll", ()=>{});
}
}
}, []);
return (
<TableContainer className="TableContainerGridStyle">
<Table className="TableStyle">
<DevicesTableHeader />
// CHANGED LINE
<TableBody ref={tableRef} className="TableBodyStyle">
<DevicesTableCell />
<DevicesTableCell />
<DevicesTableCell />
<DevicesTableCell />
<DevicesTableCell />
<DevicesTableCell />
<DevicesTableCell />
<DevicesTableCell />
<DevicesTableCell />
<DevicesTableCell />
<DevicesTableCell />
</TableBody>
</Table>
</TableContainer>
);
}
Apart from the above I think you can use another alternatives like followCursor, setting the position relative attribute to the table cell(TableCellStyle) or body. But these don't solve the problem fully.
As you are passing Table component as props children to the StateLabel component so in order to display/render we need to update StateLabel component to use props.children
export default function StateLabel({children}) {
return <div>{children}</div>;
}
Div hover not working when scrolling in chrome
My app is a dashboard of MUI <Card />s that can be dragged-and-dropped (d&d) to reorder them. The d&d logic is implemented using react-dnd and has been working well so far.
However, when I add a <DataGridPro /> as the child of a draggable <Card />, the datagrid's native Column ordering - which also is done by dragging-and-dropping - breaks. Dragging a column once or twice generates the following crash:
Invariant Violation
Cannot call hover while not dragging.
▼ 5 stack frames were expanded.
at invariant (https://bfz133.csb.app/node_modules/
react-dnd/invariant/dist/index.js:19:15
checkInvariants
https://bfz133.csb.app/node_modules/dnd-core/dist/actions/dragDrop/hover.js:33:40
DragDropManagerImpl.hover
https://bfz133.csb.app/node_modules/dnd-core/dist/actions/dragDrop/hover.js:18:5
Object.eval [as hover]
https://bfz133.csb.app/node_modules/dnd-core/dist/classes/DragDropManagerImpl.js:25:38
HTML5BackendImpl.handleTopDrop
https://bfz133.csb.app/node_modules/react-dnd-html5-backend/dist/HTML5BackendImpl.js:455:20
▲ 5 stack frames were expanded.
This screen is visible only in development. It will not appear if the app crashes in production.
Open your browser’s developer console to further inspect this error.
This error overlay is powered by `react-error-overlay` used in `create-react-app`.
You can begin dragging, the crash only happens when you let go of the mouse button.
The expected behavior is that I should be able to d&d the columns, to change their order, without issues.
Things I've tried
Removing the <DataGridPro /> and replacing that <Card /> with a text-type Card (see the code in the sandbox below) shows that d&d logic works fine with no crashes;
Disabling my app's d&d by commenting out all the relevant code causes the <DataGridPro />'s colum reordering to work as expected;
The above suggests the root cause lies in having both D&Ds work without causing an internal conflict in react-dnd, which led to me trying:
Browsing the documentation to find a way to instruct the component to use my own DndProvider or DndManager, but I couldn't find that in the API - sorry if I misread it!
Googling for the error message "Cannot call hover while not dragging", while limiting myself to contexts including the MUI library or react-dnd, yielded limited results. I found a Chrome bug that was fixed on v. 77.0.3865.120, my Chrome version is 101.0.4951.64 .
EDIT: Found this bug, but it's closed. Should I open a new one? I'd like some input on this, as I wouldn't like to bother the developers if the problem is in my code.
Minimum verified reproducible example
I made a sandbox! Click here to see it
Datagrid Component:
import React from "react";
import { DataGridPro } from "#mui/x-data-grid-pro";
import { useDemoData } from "#mui/x-data-grid-generator";
export function MyDatagridPro() {
const { data } = useDemoData({
dataSet: "Commodity",
rowLength: 5,
maxColumns: 6
});
return <DataGridPro {...data} />;
}
Card widget:
import React, { useRef } from "react";
import {
Card,
CardHeader,
CardContent,
Grid,
Typography,
Divider
} from "#mui/material";
import { useDrag, useDrop } from "react-dnd";
import { MyDatagridPro } from "./MyDatagridPro";
export function MyContentCard(props) {
const domRef = useRef(null);
const [{ isDragging }, dragBinder, previewBinder] = useDrag(
() => ({
type: "mycard",
item: () => ({
orderIndex: props.orderIndex
}),
collect: (monitor) => ({
isDragging: monitor.isDragging()
})
}),
[props]
);
const [{ handlerId, isOver }, dropBinder] = useDrop(
() => ({
accept: "mycard",
collect: (monitor) => ({
handlerId: monitor.getHandlerId(),
isOver: !!monitor.isOver()
}),
canDrop: (item, monitor) => {
if (!domRef.current) return false;
const draggingOrderIndex = item.orderIndex;
const hoveringOrderIndex = props.orderIndex;
if (draggingOrderIndex === hoveringOrderIndex) return false;
const hoverRectangleBound = domRef.current?.getBoundingClientRect();
const [hoverItemX, hoverItemY] = [
hoverRectangleBound.right - hoverRectangleBound.left,
hoverRectangleBound.bottom - hoverRectangleBound.top
];
const mousePosition = monitor.getClientOffset();
const [hoverMouseX, hoverMouseY] = [
mousePosition.x - hoverRectangleBound.left,
mousePosition.y - hoverRectangleBound.top
];
if (
(hoverMouseX < 0 || hoverMouseX > hoverItemX) &&
(hoverMouseY < 0 || hoverMouseY > hoverItemY)
) {
return false;
}
return true;
},
drop: (item) => {
props.swapper(item.orderIndex, props.orderIndex);
}
}),
[props]
);
return (
<Grid item xs={5}>
<Card
ref={(element) => {
if (element) {
domRef.current = element;
previewBinder(dropBinder(domRef));
}
}}
sx={{
height: `calc(6 * 4.5rem)`,
opacity: isDragging ? 0.3 : 1,
display: "flex",
flexDirection: "column",
border: isOver ? "2px solid rgba(0,0,0,0.5);" : ""
}}
data-handler-id={handlerId}
>
<CardHeader ref={dragBinder} title={props.title} />
<Divider />
<CardContent
sx={{
height: "100%",
display: "flex",
flexDirection: "column"
}}
>
{props.type === "text" && <Typography>{props.content}</Typography>}
{props.type === "datagrid" && <MyDatagridPro />}
</CardContent>
</Card>
</Grid>
);
}
export default MyContentCard;
App.js:
import React, { useState } from "react";
import { Grid } from "#mui/material";
import { createDragDropManager } from "dnd-core";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import { MyContentCard } from "./MyContentCard";
export const dndManager = createDragDropManager(HTML5Backend);
export default function App() {
const [cards, setCards] = useState([
{
type: "datagrid",
title: "Card 01 - A MUI DataGridPro",
content: ""
},
{
type: "text",
title: "Card 02 - Some text",
content: "Text that belongs to card 2"
}
]);
function swapCards(indexA, indexB) {
const newState = cards.slice();
const cardA = Object.assign({}, cards[indexA]);
newState[indexA] = Object.assign({}, cards[indexB]);
newState[indexB] = cardA;
setCards(newState);
}
return (
<DndProvider manager={dndManager}>
<Grid
container
spacing={1}
columns={10}
p={2}
pb={3}
mt={0}
mb={0}
// flex="1 1 auto"
overflow="auto"
sx={{
backgroundColor: "lightgray"
}}
>
{cards.map((card, i) => {
return (
<MyContentCard
key={i}
type={card.type}
title={card.title}
content={card.content}
orderIndex={i}
swapper={swapCards}
/>
);
})}
</Grid>
</DndProvider>
);
}
I'm having trouble with Intersection Observer in Gatsbyjs.
There is a fixed header that needs to change the color when some section enters 90% of the viewport.
I've created a component called IntersectionObserverComponent that renders a div with absolute position and height of 100vh. The idea is to include this component into a section that I want to track with Intersection Observer.
Here's my component
class IntersectionObserverComponent extends React.PureComponent {
constructor(props) {
super(props)
//
this.observer = null
this.ref = React.createRef()
}
componentDidMount() {
const { root, threshold, callback } = this.props
('IntersectionObserver' in window
? Promise.resolve()
: import('intersection-observer')
).then(() => {
this.observer = new IntersectionObserver(
entries => {
entries.forEach(entry => {
callback(entry)
})
},
{ threshold, root }
)
if (this.ref.current) {
this.observer.POLL_INTERVAL = 100
this.observer.observe(this.ref.current)
}
})
}
componentWillUnmount() {
if (this.ref.current && this.observer) {
this.observer.unobserve(this.ref.current)
}
}
render() {
return (
<div
ref={this.ref}
style={{
height: '100vh',
position: 'absolute',
top: 0,
left: 0,
right: 0,
}}
></div>
)
}
}
export default IntersectionObserverComponent
And here's the usage
import { handleHeaderStyle } from '../../utils/intersectionObserver'
const About = ({ isTrackable = false, handleChangeHeader = () => {} }) => {
// previousValues object is directly mutated in a handleHeaderStyle fn
const previousValues = { previousY: 0, previousRatio: 0 }
const colors = { prevColor: 'white', currColor: 'secondary' }
const handleIOCallback = entry => {
console.log(entry)
handleHeaderStyle(entry, colors, previousValues, handleChangeHeader)
}
return (
<section className="padding-top-m padding-bottom-tablet-portrait-96 header-behind background-gray-small-only">
{isTrackable ? <IO callback={handleIOCallback} /> : null}
<Container>
<Grid className="grid-padding-x">
<Cell small={12} large={8}>
<p className="margin-bottom-small-20 margin-bottom-tablet-portrait-32">
We are a brand and product development consultancy, that believes
in that design is essentially a problem-solving exercise that we
can apply to any sector, discipline or media.
</p>
<p className="margin-bottom-small-32">
We are founded on and by people who are driven by:
</p>
<ul className="arrow-bullets">
<li>
Crafting simple and notable components that build up your
brand’s value
</li>
<li>Discovery and research aimed at thoughtful practices</li>
<li>Attention to detail</li>
<li>Independence and creative freedom</li>
<li>Thinking that goes deeper</li>
</ul>
</Cell>
<Cell className="padding-top-m">
<Projects />
</Cell>
</Grid>
</Container>
</section>
)
}
export default About
And here's the function that handles logic for updating header
export const handleHeaderStyle = (
IOEntry,
colors,
previousValues,
callback
) => {
if (!IOEntry || !colors || !previousValues || typeof callback !== 'function')
return
//
const { prevColor, currColor } = colors
const currentY = IOEntry.boundingClientRect.y
const currentRatio = IOEntry.intersectionRatio
const isIntersecting = IOEntry.isIntersecting
// going up
if (currentY > previousValues.previousY) {
if (currentRatio < previousValues.previousRatio && !isIntersecting) {
callback(prevColor)
}
}
// going down
else if (currentY < previousValues.previousY && isIntersecting) {
if (currentRatio > previousValues.previousRatio) {
callback(currColor)
}
}
previousValues.previousY = currentY
previousValues.previousRatio = currentRatio
}
This is working really nice on all screen sizes when I test it in a desktop browser but the problem occurs when I test it on an actual mobile device.
Device: Iphone 7+, IOS 13.3.1
Browsers: Safari 12.1.1, Chrome 80
It works great if I don't release my finger while scrolling, but If I do, the callback is not fired consistently. I've also tried setting the POLL_INTERVAL to 100ms but it didn't help.
I'm suspecting that has something to do with the way iOS Safari handles the scroll event (https://github.com/martinlaxenaire/curtainsjs/issues/18)
Here's the test link on Netlify - https://nifty-einstein-c4cf08.netlify.com/
I'm trying to figure it out for days now, thanks in advance
I am trying to migrate a code I created in JS/JQuery to ReactJS. The code uses the library fullpage.js. The aim is to change the title according to the section on focus. I am struggling to correctly capture the properties of elements in the DOM using Refs. I tried to follow the ReactJS documentation but the example in the docs made everything more confusing.
My question is, how can I store these properties and then apply it using CSS on the required DOM element? Thank you in advance.
Pseudocode
Store title width
Store title height
Apply these properties to the
parents' frame and mask
Listen to the scroll events of fullpage.js
and translate the title position accordingly
Codepen (JS/JQuery)
$(document).ready(function() {
var titleWidth = $(".title").outerWidth();
var titleHeight = $(".title").outerHeight();
$("#mask").css({ height: titleHeight + "px", width: titleWidth + "px" });
$("#frame").css("top", titleHeight);
new fullpage("#fullpage", {
sectionsColor: ["yellow", "orange", "#C0C0C0", "#ADD8E6"],
afterRender: function() {
$("#frame").transition({ top: "-=" + titleHeight, delay: 1000 });
},
onLeave: function(origin, destination, direction) {
var leavingSection = this;
//after leaving section 2
if (direction == "down") {
$("#frame").transition({ top: "-=" + titleHeight });
} else if (direction == "up") {
$("#frame").transition({ top: "+=" + titleHeight });
}
}
});
});
Codesandbox (ReactJS)
import React from "react";
import ReactDOM from "react-dom";
import "fullpage.js/vendors/scrolloverflow"; // Optional. When using scrollOverflow:true
import ReactFullpage from "#fullpage/react-fullpage";
import "./styles.css";
class MySection extends React.Component {
render() {
return (
<div className="section">
<h3>{this.props.content}</h3>
</div>
);
}
}
const anchors = ["firstPage", "secondPage", "thirdPage"];
const FullpageWrapper = () => (
<ReactFullpage
anchors={anchors}
navigation
navigationTooltips={anchors}
sectionsColor={["#282c34", "#ff5f45", "#0798ec"]}
onLeave={(origin, destination, direction) => {
console.log("onLeave event", { origin, destination, direction });
//after leaving section 2
if (origin.index === 1 && direction === "down") {
alert("Going to section 3!");
} else if (origin.index === 1 && direction === "up") {
alert("Going to section 1!");
}
}}
render={({ state, fullpageApi }) => {
console.log("render prop change", state, fullpageApi); // eslint-disable-line no-console
return (
<div>
<MySection content={"Slide down!"} />
<MySection content={"Keep going!"} />
<MySection content={"Slide up!"} />
</div>
);
}}
/>
);
class Index extends React.Component {
constructor(props) {
super(props);
this.title = React.createRef();
// this.title = null;
// this.titleRef = element => {
// this.title = element;
// };
// this.setTitle = () => {
// Focus the text input using the raw DOM API
// if (this.title) this.title.current.offsetWidth;
// };
}
componentDidMount() {
// console.log(this.setTitle())
const titleWidth = this.title.current.offsetWidth;
const titleHeight = this.title.current.offsetHeight;
console.log(titleWidth, titleHeight);
}
render() {
return (
<div class="wrapper">
<div id="mask">
<div id="frame">
<h1 ref={this.title} class="title">
One
</h1>
<h1 ref={this.title} class="title">
Two
</h1>
<h1 ref={this.title} class="title">
Three
</h1>
<h1 ref={this.title} class="title">
Four
</h1>
</div>
</div>
<div class="content">
<FullpageWrapper />
</div>
</div>
);
}
}
ReactDOM.render(<Index />, document.getElementById("react-root"));
How can I show different DIV content based on the current index of a slide? This is a component which I'm looping through a MAP and the image, content, and id is inside the DATA object.
What I'm trying to have here to show different HTML/Content based on the currentIndex how can i get this to work?
What am I doing wrong? Currently, it's displaying all the index slides on EACH slide.
Thanks in advance!
import React, { Component } from 'react';
// Components
import QuizSlide from '../Slider/Slide';
// import QuizMain from '../Quiz/QuizMain';
import LeftArrow from '../Arrows/LeftArrow';
import RightArrow from '../Arrows/RightArrow';
import Footer from '../Slider/Footer';
import QuizLogo from 'images/QuizLogo.svg';
// App Styles
import 'sass/root.scss';
export default class QuizSlider extends Component {
// The Constructor
constructor(props) {
super(props);
this.state = {
footerURL: 'http://www.google.nl',
footerText: 'Naar website STC',
copyright: 'Friends For Brands 2018',
currentIndex: 0,
translateValue: 0,
data: [
{index: 1, content: 'Ga voor grenzeloos', image: 'https://images.pexels.com/photos/219014/pexels-photo-219014.jpeg?auto=compress&cs=tinysrgb&dpr=1&h=650&w=940'},
{index: 2, content: 'Sectoren', image: 'https://images.pexels.com/photos/259984/pexels-photo-259984.jpeg?auto=compress&cs=tinysrgb&dpr=1&h=650&w=940'},
{index: 3, content: 'Wat wil jij?', image: 'https://images.pexels.com/photos/355952/pexels-photo-355952.jpeg?auto=compress&cs=tinysrgb&dpr=1&h=650&w=940'},
{index: 4, content: 'Vlogs', image: 'https://images.pexels.com/photos/320617/pexels-photo-320617.jpeg?auto=compress&cs=tinysrgb&dpr=1&h=650&w=940'},
{index: 5, content: 'Belangrijke data', image: 'https://images.pexels.com/photos/1181316/pexels-photo-1181316.jpeg?auto=compress&cs=tinysrgb&dpr=1&h=650&w=940'}
]
}
}
// Functions
PrevSlide = () => {
if(this.state.currentIndex === 0) {
return this.setState({
currentIndex: 0,
translateValue: 0
})
}
// This will not run if we met the if condition above
this.setState(PrevState => ({
currentIndex: PrevState.currentIndex - 1,
translateValue: PrevState.translateValue + (this.slideWidth())
}));
}
NextSlide = () => {
const slideWidth = this.slideWidth();
// Exiting the method early if we are at the end of the images array.
// We also want to reset currentIndex and translateValue, so we return
// to the first image in the array.
if(this.state.currentIndex === this.state.data.length - 1) {
return this.setState({
currentIndex: 0,
translateValue: 0
})
}
// This will not run if we met the if condition above
this.setState(NextState => ({
currentIndex: NextState.currentIndex + 1,
translateValue: NextState.translateValue + -(slideWidth)
}));
}
slideWidth = () => {
return document.querySelector('.QuizSlide').clientWidth
}
// Render
render() {
return (
<div className="QuizSlider">
<div className="QuizLogo">
<img src={QuizLogo}/>
</div>
<LeftArrow PrevSlide={this.PrevSlide} />
<RightArrow NextSlide={this.NextSlide} />
<div className="slider-wrapper" style={{ transform: `translateX(${this.state.translateValue}px)` }}>
{
this.state.data.map((props, index) => (
<QuizSlide key={index} content={props.content} id={index + 1} image={props.image} />
))
}
</div>
<Footer url={this.state.footerURL} text={this.state.footerText} copyright={this.state.copyright} />
</div>
)
}
}
import React from 'react';
const QuizSlide = ({image, content, id}) => {
const currentIndexSlide = id;
if(currentIndexSlide === 1) {
<div className="slide-1">Show this data on 1.</div>
}
if(currentIndexSlide === 2) {
<div className="slide-2">Show this data on 2.</div>
}
if(currentIndexSlide === 3) {
<div className="slide-3">Show this data on 3.</div>
}
return (
<div className="QuizSlide" style={{backgroundImage: `url(${image})`}}>
<div className="QuizSlide--content">
<h2>{content}</h2>
{id}
</div>
</div>
)
}
export default QuizSlide;
In the return section which renders the HTML DOM, you are displaying the entire content. Every time the QuizSlide component is called on iterating the array through a map and hence all the data is displayed.
So, the restriction should be within the render section. The conditional rendering should be something like:
return (
<div className="QuizSlide" style={{backgroundImage: `url(${image})`}}>
<div className="QuizSlide--content">
<h2>{content}</h2>
{id}
{id === '1' &&
<div className="slide-1">
Show this data on 1.
</div>
}
{id === '2' &&
<div className="slide-2">
Show this data on 2.
</div>
}
</div>
</div>
)
Define a variable using let before your if statements, then assign a value to it inside those, displaying that inside your return.
const QuizSlide = ({image, content, id}) => {
const currentIndexSlide = id;
let slide;
if(currentIndexSlide === 1) {
slide = <div className="slide-1">Show this data on 1.</div>
}
if(currentIndexSlide === 2) {
slide = <div className="slide-2">Show this data on 2.</div>
}
if(currentIndexSlide === 3) {
slide = <div className="slide-3">Show this data on 3.</div>
}
return (
<div className="QuizSlide" style={{backgroundImage: `url(${image})`}}>
<div className="QuizSlide--content">
<h2>{content}</h2>
{id}
{slide}
</div>
</div>
)
}
export default QuizSlide;