Topic: MDB React Card Flipping
kpickering asked 5 years ago
**Expected behavior** I am using props to load in multiple flipping cards, I am able to render the cards but when I go to update the state so the cards are able to flip individually it states that there is no state defined.
**Actual behavior** Page is unable to load as it stating there is no state defined and the function "handleFlipping" is also not defined.
**Resources (screenshots, code snippets etc.)**
Here is a link to the project without adding in the state feature so you able to see how it works.
https://agile-river-38619.herokuapp.com/meraki-oil
here is the code for the two pages --
Card Page: import React from "react"; import {MDBCard, MDBCol, MDBCardBody, MDBRotatingCard, MDBIcon} from "mdbreact"; import Ingredients from "../ingredients"; import ingredients from "../ingredients.json";
const IngredientsCard = props =>{
state = {
ingredients,
flipped1: false,
flipped2: false,
flipped3: false,
flipped4: false,
flipped5: false,
flipped6: false,
flipped7: false,
flipped8: false,
flipped9: false,
flipped10: false,
flipped11: false,
flipped12: false,
flipped13: false,
flipped14: false,
flipped15: false,
flipped16: false,
flipped17: false,
flipped18: false,
flipped19: false,
flipped20: false,
flipped21: false,
flipped22: false,
flipped23: false,
flipped24: false,
flipped25: false,
flipped26: false,
flipped27: false,
flipped28: false,
flipped29: false,
flipped30: false,
flipped31: false,
flipped32: false,
flipped33: false,
flipped34: false,
}
handleFlipping = id => () => {
const cardId = flipped${id}
;
this.setState({ [cardId]: !this.state[cardId] });
}
return(
<div>
<MDBCol style={{ width: "22rem", height: "18rem" }}>
<MDBRotatingCard flipped={this.state.props.flipped} className="text-center h-100 w-100">
<MDBCard className="face front">
<MDBCardBody>
<img className="card-img-top" src={Ingredients[props.image]} alt={props.name} />
<h4 className="font-weight-bold mb-3">{props.name}</h4>
<a href="#!" className="rotate-btn text-dark" data-card="card-4" onClick={this.handleFlipping(props.key)}>
<MDBIcon icon="redo" /> Click here to learn more
</a>
</MDBCardBody>
</MDBCard>
<MDBCard className="face back" style={{ height: "300px" }}>
<MDBCardBody>
<h4 className="font-weight-bold">Benefits</h4>
<hr />
<p>
{props.body} </p><hr />
<a href="#!" className="rotate-btn text-dark" data-card="card-4" onClick={this.handleFlipping(props.key)}>
<MDBIcon icon="undo" /> Click here to rotate back
</a>
</MDBCardBody>
</MDBCard>
</MDBRotatingCard>
</MDBCol>
</div>
)
}
export default IngredientsCard;
Loading into Carousel
import React, { Component } from "react"; import "../index.css"; import { MDBContainer } from "mdbreact"; import Carousel from "react-multi-carousel"; import ingredients from "../ingredients.json"; import IngredientsCard from "./IngredientsCard.js";
class IngredientsCarousel extends Component {
state = {
ingredients,
flipped1: false,
flipped2: false,
flipped3: false,
flipped4: false,
flipped5: false,
flipped6: false,
flipped7: false,
flipped8: false,
flipped9: false,
flipped10: false,
flipped11: false,
flipped12: false,
flipped13: false,
flipped14: false,
flipped15: false,
flipped16: false,
flipped17: false,
flipped18: false,
flipped19: false,
flipped20: false,
flipped21: false,
flipped22: false,
flipped23: false,
flipped24: false,
flipped25: false,
flipped26: false,
flipped27: false,
flipped28: false,
flipped29: false,
flipped30: false,
flipped31: false,
flipped32: false,
flipped33: false,
flipped34: false,
}
handleFlipping = id => () => {
const cardId = `flipped${id}`;
this.setState({ [cardId]: !this.state[cardId] });
}
render(){
const responsive = {
desktop: {
breakpoint: { max: 3000, min: 1024 },
items: 5,
slidesToSlide: 1, // optional, default to 1.
},
tablet: {
breakpoint: { max: 1024, min: 464 },
items: 2,
slidesToSlide: 2, // optional, default to 1.
},
mobile: {
breakpoint: { max: 464, min: 0 },
items: 1,
slidesToSlide: 1, // optional, default to 1.
},
};
return(
<div>
<MDBContainer>
<Carousel
swipeable={true} draggable={true} showDots={false} responsive={responsive} ssr={true} // means to render carousel on server-side. infinite={true} keyBoardControl={true} customTransition="all .5" transitionDuration={500} containerClass="carousel-container" removeArrowOnDeviceType={["tablet", "mobile"]} deviceType={this.props.deviceType} dotListClass="custom-dot-list-style" itemClass="carousel-item-padding-40-px"
{this.state.ingredients.map(merakiIngredients =>(
<IngredientsCard
id={merakiIngredients.id}
key={merakiIngredients.key}
name={merakiIngredients.name}
image={merakiIngredients.image}
flipped={merakiIngredients.flipped}
flipping={merakiIngredients.flipping}
/>
))}
; ) }
}
export default IngredientsCarousel;
Jakub Chmura staff premium answered 5 years ago
hi @kpickering,
First of all, you can't manage the state
in functional component as you do in an IngredientsCard
component.
Your code has many errors and it's hard for me to tell you what's wrong with it.
I tried to repair some of the errors. Check this code now and let me know that my solution works in your case.
First Component:
import React, { Component } from 'react';
import {
MDBCard,
MDBCol,
MDBCardBody,
MDBRotatingCard,
MDBIcon
} from 'mdbreact';
import Ingredients from '../ingredients';
import ingredients from '../ingredients.json';
class IngredientsCard extends Component {
state = {
ingredients,
flipped1: false,
flipped2: false,
flipped3: false,
flipped4: false,
flipped5: false,
flipped6: false,
flipped7: false,
flipped8: false,
flipped9: false,
flipped10: false,
flipped11: false,
flipped12: false,
flipped13: false,
flipped14: false,
flipped15: false,
flipped16: false,
flipped17: false,
flipped18: false,
flipped19: false,
flipped20: false,
flipped21: false,
flipped22: false,
flipped23: false,
flipped24: false,
flipped25: false,
flipped26: false,
flipped27: false,
flipped28: false,
flipped29: false,
flipped30: false,
flipped31: false,
flipped32: false,
flipped33: false,
flipped34: false
};
handleFlipping = id => {
const cardId = `flipped${id}`;
this.setState({ [cardId]: !this.state[cardId] });
};
render() {
const { name, image, key, body, flipped } = this.props;
return (
<div>
<MDBCol style={{ width: '22rem', height: '18rem' }}>
<MDBRotatingCard
flipped={flipped}
className='text-center h-100 w-100'
>
<MDBCard className='face front'>
<MDBCardBody>
<img
className='card-img-top'
src={Ingredients[image]}
alt={name}
/>
<h4 className='font-weight-bold mb-3'>{name}</h4>
<a
href='#!'
className='rotate-btn text-dark'
data-card='card-4'
onClick={this.handleFlipping(key)}
>
<MDBIcon icon='redo' /> Click here to learn more
</a>
</MDBCardBody>
</MDBCard>
<MDBCard className='face back' style={{ height: '300px' }}>
<MDBCardBody>
<h4 className='font-weight-bold'>Benefits</h4>
<hr />
<p>{body} </p>
<hr />
<a
href='#!'
className='rotate-btn text-dark'
data-card='card-4'
onClick={this.handleFlipping(key)}
>
<MDBIcon icon='undo' /> Click here to rotate back
</a>
</MDBCardBody>
</MDBCard>
</MDBRotatingCard>
</MDBCol>
</div>
);
}
}
export default IngredientsCard;
And the second component.
import React, { Component } from 'react';
import '../index.css';
import { MDBContainer } from 'mdbreact';
import Carousel from 'react-multi-carousel';
import ingredients from '../ingredients.json';
import IngredientsCard from './srap';
class IngredientsCarousel extends Component {
state = {
ingredients,
flipped1: false,
flipped2: false,
flipped3: false,
flipped4: false,
flipped5: false,
flipped6: false,
flipped7: false,
flipped8: false,
flipped9: false,
flipped10: false,
flipped11: false,
flipped12: false,
flipped13: false,
flipped14: false,
flipped15: false,
flipped16: false,
flipped17: false,
flipped18: false,
flipped19: false,
flipped20: false,
flipped21: false,
flipped22: false,
flipped23: false,
flipped24: false,
flipped25: false,
flipped26: false,
flipped27: false,
flipped28: false,
flipped29: false,
flipped30: false,
flipped31: false,
flipped32: false,
flipped33: false,
flipped34: false
};
handleFlipping = id => () => {
const cardId = `flipped${id}`;
this.setState({ [cardId]: !this.state[cardId] });
};
render() {
const responsive = {
desktop: {
breakpoint: { max: 3000, min: 1024 },
items: 5,
slidesToSlide: 1 // optional, default to 1.
},
tablet: {
breakpoint: { max: 1024, min: 464 },
items: 2,
slidesToSlide: 2 // optional, default to 1.
},
mobile: {
breakpoint: { max: 464, min: 0 },
items: 1,
slidesToSlide: 1 // optional, default to 1.
}
};
return (
<div>
<MDBContainer>
<Carousel
swipeable={true}
draggable={true}
showDots={false}
responsive={responsive}
ssr={true}
// means to render carousel on server-side. infinite={true} keyBoardControl={true} customTransition="all .5" transitionDuration={500} containerClass="carousel-container" removeArrowOnDeviceType={["tablet", "mobile"]} deviceType={this.props.deviceType} dotListClass="custom-dot-list-style" itemClass="carousel-item-padding-40-px"
>
{this.state.ingredients.map(merakiIngredients => (
<IngredientsCard
id={merakiIngredients.id}
key={merakiIngredients.key}
name={merakiIngredients.name}
image={merakiIngredients.image}
flipped={merakiIngredients.flipped}
flipping={merakiIngredients.flipping}
/>
))}
</Carousel>
</MDBContainer>
</div>
);
}
}
export default IngredientsCarousel;
Best regards,
Kuba
kpickering answered 5 years ago
Jakub Chmura staff premium answered 5 years ago
Hi @kpickering
Error from your screenshot means that your function has fallen into an infinite loop when you try to set your state by clicking the card. You need to check why this function is calling so many times.
I see that in your code is some errors.
Look at your sample that you send me. You set the same state in your IngredientsCarousel
component and IngredientsCard
component. You need to decide on which component you want to manage your state. At your IngredientsCarousel component, you write there a handleFlipping
method and you're not calling them.
If there is anything else I could do for you do not hesitate to ask me. I'll be happy to help you.
Best Regards,
Kuba
kpickering answered 5 years ago
Thank you for your help with this, I am still very new at this. I have solved the problem with the continuous loops by doing this:
onClick={() => this.handleFlipping(id)}
But now, all of the cards are flipped to the back without any information on it, I am clearly still missing something, and I would really like if you could point me in the direction I should be looking!
import React, { Component } from "react";
import {MDBCard, MDBCol, MDBCardBody, MDBRotatingCard, MDBIcon} from "mdbreact";
import Ingredients from "../ingredients";
import ingredients from "../ingredients.json";
class IngredientsCard extends Component {
state = {
ingredients,
flipped1: false,
flipped2: false,
flipped3: false,
flipped4: false,
flipped5: false,
flipped6: false,
flipped7: false,
flipped8: false,
flipped9: false,
flipped10: false,
flipped11: false,
flipped12: false,
flipped13: false,
flipped14: false,
flipped15: false,
flipped16: false,
flipped17: false,
flipped18: false,
flipped19: false,
flipped20: false,
flipped21: false,
flipped22: false,
flipped23: false,
flipped24: false,
flipped25: false,
flipped26: false,
flipped27: false,
flipped28: false,
flipped29: false,
flipped30: false,
flipped31: false,
flipped32: false,
flipped33: false,
flipped34: false
};
handleFlipping = id => {
const cardId = `flipped${id}`;
this.setState({ [cardId]: !this.state[cardId] });
};
render() {
const { name, image, id, body, flipped } = this.props;
return (
<div>
<MDBCol style={{ width: '22rem', height: '18rem' }}>
<MDBRotatingCard
flipped={flipped}
className='text-center h-100 w-100'
>
<MDBCard className='face front'>
<MDBCardBody>
<img
className='card-img-top'
src={Ingredients[image]}
alt={name}
/>
<h4 className='font-weight-bold mb-3'>{name}</h4>
<a
href='#!'
className='rotate-btn text-dark'
data-card='card-4'
onClick={() => this.handleFlipping(id)}
>
<MDBIcon icon='redo' /> Click here to learn more
</a>
</MDBCardBody>
</MDBCard>
<MDBCard className='face back' style={{ height: '300px' }}>
<MDBCardBody>
<h4 className='font-weight-bold'>Benefits</h4>
<hr />
<p>{body} </p>
<hr />
<a
href='#!'
className='rotate-btn text-dark'
data-card='card-4'
onClick={() => this.handleFlipping(id)}
>
<MDBIcon icon='undo' /> Click here to rotate back
</a>
</MDBCardBody>
</MDBCard>
</MDBRotatingCard>
</MDBCol>
</div>
);
and
import React, { Component } from "react";
import "../index.css";
import Carousel from "react-multi-carousel";
import ingredients from "../ingredients.json";
import IngredientsCard from "./IngredientsCard.js";
class IngredientsCarousel extends Component {
state = {
ingredients
};
render() {
const responsive = {
desktop: {
breakpoint: { max: 3000, min: 1024 },
items: 5,
slidesToSlide: 1 // optional, default to 1.
},
tablet: {
breakpoint: { max: 1024, min: 464 },
items: 2,
slidesToSlide: 2 // optional, default to 1.
},
mobile: {
breakpoint: { max: 464, min: 0 },
items: 1,
slidesToSlide: 1 // optional, default to 1.
}
};
return (
<div>
<Carousel
swipeable={true}
draggable={true}
showDots={false}
responsive={responsive}
ssr={true}
// means to render carousel on server-side. infinite={true} keyBoardControl={true} customTransition="all .5" transitionDuration={500} containerClass="carousel-container" removeArrowOnDeviceType={["tablet", "mobile"]} deviceType={this.props.deviceType} dotListClass="custom-dot-list-style" itemClass="carousel-item-padding-40-px"
>
{this.state.ingredients.map(merakiIngredients => (
<IngredientsCard
id={merakiIngredients.id}
key={merakiIngredients.id}
name={merakiIngredients.name}
image={merakiIngredients.image}
flipped={merakiIngredients.flipped}
flipping={merakiIngredients.flipping}
/>
))}
</Carousel>
</div>
);
} }
export default IngredientsCarousel;
Jakub Chmura staff premium answered 5 years ago
Hi @kpickering
Your IngredientsCarousel looks fine but IngrediensCard still has some issue.
- If you use
IngreediendsCard
as a component to render a card in other components ( as you do in your example) you don't need to set state from 1 to x cards because thestate
and any other functions fromIngreediendsCard
that you do not export into other places create a closed environment. Thestate
of each card belongs only to it. - When we delete unnecessary state we don't need any more flipping id's in
handleFlipping
function because we use only one state. - In
MDBRotatingCard
component in flipped property, you need to refer directly to the state, which is not a prop.
Check my code and let me know if it will work.
import React, { Component } from 'react';
import {
MDBCard,
MDBCol,
MDBCardBody,
MDBRotatingCard,
MDBIcon
} from 'mdbreact';
import Ingredients from '../ingredients';
import ingredients from '../ingredients.json';
class IngredientsCard extends Component {
state = {
ingredients,
flipped: false
};
handleFlipping = () => {
this.setState({ flipped: !this.state.flipped });
};
render() {
const { name, image, body } = this.props;
return (
<div>
<MDBCol style={{ width: '22rem', height: '18rem' }}>
<MDBRotatingCard
flipped={this.state.flipped}
className='text-center h-100 w-100'
>
<MDBCard className='face front'>
<MDBCardBody>
<img
className='card-img-top'
src={Ingredients[image]}
alt={name}
/>
<h4 className='font-weight-bold mb-3'>{name}</h4>
<a
href='#!'
className='rotate-btn text-dark'
data-card='card-4'
onClick={() => this.handleFlipping()}
>
<MDBIcon icon='redo' /> Click here to learn more
</a>
</MDBCardBody>
</MDBCard>
<MDBCard className='face back' style={{ height: '300px' }}>
<MDBCardBody>
<h4 className='font-weight-bold'>Benefits</h4>
<hr />
<p>{body} </p>
<hr />
<a
href='#!'
className='rotate-btn text-dark'
data-card='card-4'
onClick={() => this.handleFlipping()}
>
<MDBIcon icon='undo' /> Click here to rotate back
</a>
</MDBCardBody>
</MDBCard>
</MDBRotatingCard>
</MDBCol>
</div>
);
}
}
export default IngredientsCard;
Best regards,
Kuba
kpickering answered 5 years ago
Yes, it worked, thank you!
Jakub Chmura staff premium commented 5 years ago
@kpickering, No problem. I'm happy I could help.
Best, Kuba
FREE CONSULTATION
Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.
Answered
- User: Free
- Premium support: No
- Technology: MDB React
- MDB Version: 4.19.2
- Device: Samsung Ultra Book ativ
- Browser: mozilla
- OS: linux
- Provided sample code: No
- Provided link: Yes