I am running sample application in react-native. I have 2 buttons i.e., forward and backward. How to write the functionality for below mentioned 2 points.
1. When i click forward button then screenshot is shown below.
2. When i click backward button then screenshot is shown below.
I wrote this in React.js, you could port it
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
imageIndex: 2
}
this.setIndex = this.setIndex.bind(this)
}
setIndex(index) {
this.setState(Object.assign({}, this.state, {
imageIndex: index
}));
}
render() {
const { imageIndex } = this.state
let imgClasses = [
"ph bg-green",
"ph bg-blue",
"ph bg-green",
"ph bg-red"
]
return (
<div className="container">
{ imgClasses.map((img, i) =>
<div onClick={ () => this.setIndex(i) }
className={`${img}${ imageIndex == i ? " active" : ""}`}
style = {{
top: 60 * i,
left: 60 * i
}}>
</div>
) }
</div>
)
}
}
ReactDOM.render( <App /> , document.getElementById('app'));
.container {
position: relative;
}
.ph {
width: 100px;
height: 100px;
margin: 4px;
position: absolute;
border: 1px #fff solid
}
.ph.active {
z-index: 10;
}
.bg-green {
background: #8BC34A;
}
.bg-blue {
background: #03A9F4;
}
.bg-red {
background: #E91E63;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Related
I'm trying to implement like function by using redux and map function to use states in other components. I used redux not using useState([]) because I thought it is better way to manage states. I made the button changed when button is clicked. But they are sharing same state so it is changed at the same time. To solve this problem, I think I should add this state in array. And here comes my question. How can I add state declared in redux to manage state separately? And is this way correct? I'll upload concrete code including redux by using codesandbox. I'd appreciate it if you let me know, thanks.
Clothes
import React, { useState } from "react";
import styled from "styled-components";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faHeart } from "#fortawesome/free-solid-svg-icons";
import { faHome } from "#fortawesome/free-solid-svg-icons";
import { useDispatch, useSelector } from "react-redux";
const array = [
{
id: "1",
name: "vest",
img:
"https://shopimg.kakaofriendsgolf.com/live/images/2022/9/7/10/918997_1662515279620.png",
price: "10000"
},
{
id: "2",
name: "shirts",
img:
"https://shopimg.kakaofriendsgolf.com/live/images/2022/8/23/18/551886_1661246483199.png",
price: "12000"
},
{
id: "3",
name: "pants",
img:
" https://shopimg.kakaofriendsgolf.com/live/images/2022/8/22/18/18783_1661159105201.png",
price: "15000"
}
];
export default function Clothes() {
const isClick = useSelector((state) => state.CheckLike.isClick);
const dispatch = useDispatch();
// change Icon
const setHide = (e) => {
dispatch({ type: "False" });
};
const setShow = (e) => {
dispatch({ type: "True" });
};
return (
<Wrap>
<div className="productCard">
{array.map((content, idx) => {
return (
<div key={idx} className="productCard__wrap">
<img src={content.img} className="productCard__img" />
<div className="productCard__name">
<div>
<h3 className="productCard__title">{content.name}</h3>
<div className="productCard__priceWrap">
{content.price
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ",")}
</div>
</div>
<div className="productCard__likeWrap">
{/* show heart and house icon according to state */}
{isClick ? (
<div
onClick={() => {
setHide();
}}
>
<FontAwesomeIcon icon={faHeart} />
</div>
) : (
<div
onClick={() => {
setShow();
}}
>
<FontAwesomeIcon icon={faHome} />
</div>
)}
</div>
</div>
</div>
);
})}
</div>
</Wrap>
);
}
const Wrap = styled.div`
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: scroll;
.productCard {
display: flex;
position: absolute;
top: calc(50vh - 120px);
left: calc(50vw - 180px);
width: "228px";
height: "351px";
padding-right: 8px;
padding-left: 8px;
border: solid 1px black;
}
.productCard__wrap {
border: 1px solid grey;
line-height: 1.428571429;
background-color: #fff;
}
.productCard__img {
width: 228px;
height: 228px;
}
.productCard__name {
padding-bottom: 30px;
position: relative;
padding: 8px 8px 0 8px;
min-height: 118px;
text-align: left;
}
.productCard__title {
font-size: 18px;
margin-top: 0;
margin-bottom: 2px;
padding-right: 37px;
line-height: 1.3;
margin-block-start: 1em;
margin-block-end: 1em;
}
.productCard__priceWrap {
font-size: 18px;
margin-top: 5px;
vertical-align: middle;
margin: 0 0 9px;
margin-block-start: 1em;
margin-block-end: 1em;
text-align: left;
}
.productCard__likeWrap {
position: absolute;
top: -5px;
right: 0;
padding: 0;
height: 40px;
line-height: 37px;
white-space: normal;
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
}
`;
codesandbox
https://codesandbox.io/s/likepractice-tpcv7l?file=/src/components/Clothes.jsx
There could be many approaches, but assuming that the goal is to make the like button work for individual items and save the liked items in the store, I think the solution of using an array as a state is suitable in the use case.
Forked demo with modification: codesandbox
Configure the state as an array and create matching reducers, here the product id is saved to the state array when liked, but this is an optional approach.
const initailState = {
isClick: [],
};
const CheckLike = (state = initailState, action) => {
switch (action.type) {
case "True":
return {
...state,
isClick: [...state.isClick, action.id],
};
case "False":
return {
...state,
isClick: state.isClick.filter((id) => id !== action.id),
};
default:
return {
...state,
};
}
};
Edit the event handler to dispatch the item id to be added or removed from the state array:
const setHide = (id) => {
dispatch({ type: "False", id });
};
const setShow = (id) => {
dispatch({ type: "True", id });
};
Check if product id content.id is included in the state array as a condition for rendering the icons, and wire up the icons to send content.id to the events:
<div className="productCard__likeWrap">
{isClick.includes(content.id) ? (
<div
onClick={() => {
setHide(content.id);
}}
>
<FontAwesomeIcon icon={faHeart} />
</div>
) : (
<div
onClick={() => {
setShow(content.id);
}}
>
<FontAwesomeIcon icon={faHome} />
</div>
)}
</div>
if I'm guessing correctly your problem is that the button click changes all the buttons.
for this issue, you don't need redux. use redux when you want to manage a global state used in multiple components(ex, session).
solution for your problem is, create a new component for each product card and there manage the state of the button.
and to store which products are on the wishlist you can store that in redux.
I am trying to write a useState() Hook, and perhaps add useEffect() to solve active state on two buttons. It is Delivery buttons that needs the first button-delivery to be active using CSS change, and if clicked on second button, PickUp, it should change CSS UI to stay active.
And yes if it is anyhow possible i want to use Hooks.
Is there any possible way to have it done on this way?
const Header = props => {
const [isActive, setIsActive] = useState(false);
function changeButtons () {
setIsActive = (!isActive)
};
return (
<Fragment>
<header className={classes.header}>
<div className={classes.logo} onClick={reload}>
<div >
Foodzilla
</div>
</div>
<div className={classes.delivery}>
<div
className={isActive ? classes.deliveryAction : classes.deliveryChoice}
onChange={changeButtons}
>Delivery</div>
<div className={classes.or}>or</div>
<div
className={isActive ? classes.pickUpAction : classes.pickUpChoice}
onChange={changeButtons}
>Pick Up</div>
</div>
Okay, so I did a mockup of what you are trying to do (I think :D). Here is a link to the working solution: https://codesandbox.io/s/quiet-mountain-68e10k?file=/src/styles.css:59-775.
The code is also below. There is definitely some refactoring that can be done, but I wanted to at least get you started on the right path.
Quick Summary:
Blue is Cicked (takes precedence over hover and default when active).
Green is Hovered (goes back to default when outside the div).
Red is Default (if not clicked or hovered, show red).
import "./styles.css";
import React, { useState } from "react";
export default function App() {
const [isDeliveryClicked, setIsDeliveryClicked] = useState(false);
const [isPickupClicked, setIsPickupClicked] = useState(false);
const [isDeliveryHovered, setIsDeliveryHovered] = useState(false);
const [isPickupHovered, setIsPickupHovered] = useState(false);
const handleClick = (e) => {
if (e.target.className.includes("delivery")) {
setIsDeliveryClicked(true);
setIsDeliveryHovered(false);
if (isDeliveryClicked === true) {
setIsDeliveryClicked(false);
setIsDeliveryHovered(true)
}
} else if (e.target.className.includes("pickup")) {
setIsPickupClicked(true);
setIsPickupHovered(false);
if (isPickupClicked === true) {
setIsPickupClicked(false);
setIsPickupHovered(true)
}
}
};
const handleOnMouseOver = (e) => {
if (e.target.className.includes("delivery")) {
setIsDeliveryHovered(true);
} else if (e.target.className.includes("pickup")) {
setIsPickupHovered(true);
}
};
const handleOnMouseLeave = (e) => {
if (e.target.className.includes("delivery")) {
setIsDeliveryHovered(false);
} else if (e.target.className.includes("pickup")) {
setIsPickupHovered(false);
}
};
const handleClassStyler = (buttonType) => {
if (buttonType === 'delivery') {
if (isDeliveryClicked === true) {
return "deliveryClicked";
} else if (isDeliveryHovered === true && isDeliveryClicked === false) {
return "deliveryHovered";
} else if (isDeliveryClicked === false && isDeliveryHovered === false) {
return "delivery";
}
} else if (buttonType === 'pickup'){
if (isPickupClicked === true) {
return "pickupClicked";
} else if (isPickupHovered === true && isPickupClicked === false) {
return "pickupHovered";
} else if (isPickupClicked === false && isPickupHovered === false) {
return "pickup";
}
}
};
return (
<div className="App">
<div
onMouseOver={handleOnMouseOver}
onMouseLeave={handleOnMouseLeave}
onClick={handleClick}
className={handleClassStyler('delivery)}
>
Delivery
</div>
<div
onMouseOver={handleOnMouseOver}
onMouseLeave={handleOnMouseLeave}
onClick={handleClick}
className={handlePickupClassStyler('pickup')}
>
Pick Up
</div>
</div>
);
}
The CSS I used for above is:
.delivery {
width: 100px;
height: 100px;
background-color: red;
border: solid black 5px;
margin: 5px;
}
.deliveryClicked {
width: 100px;
height: 100px;
background-color: blue;
border: solid black 5px;
margin: 5px;
}
.deliveryHovered {
width: 100px;
height: 100px;
background-color: green;
border: solid black 5px;
margin: 5px;
}
.pickup {
width: 100px;
height: 100px;
background-color: red;
border: solid black 5px;
margin: 5px;
}
.pickupClicked {
width: 100px;
height: 100px;
background-color: blue;
border: solid black 5px;
margin: 5px;
}
.pickupHovered {
width: 100px;
height: 100px;
background-color: green;
border: solid black 5px;
margin: 5px;
}
Well,
After reading all the input (which was incredibly helpful to get my logic straight) i have come with an idea and some refactoring:
However, as almost close to a solution i still need to solve my default state. And i am stuck again.
Default state should be Delivery, and the (button) should have active CSS as well.
Also, when i add CSS .deliveryChoice:hover {} it does not respond. My guess is that, as it is a child component the header don't respond as it reads no inside buttons.
Right now, they are both off.
My Header component:
const Header = props => {
return (
<Fragment>
<header className={classes.header}>
<div className={classes.logo} onClick={reload}>
<div >
Foodzilla
</div>
</div>
<div className={classes.delivery}>
<DeliveryButton
className={classes.deliveryChoice}
/>
</div>
<div>
<div className={classes.deliveryAdress}>
Delivery to:
</div>
</div>
<div className={classes.deliveryTime}>
<div >
Choose time: Now
</div>
</div>
<HeaderCartButton onClick={props.onShowCart} />
</header>
<div className={classes['main-image']}>
<img src={mealsImg} />
</div>
</Fragment>
And my DeliveryButton:
const deliveryChoice = [{ name: 'Delivery' }, { name: 'PickUp' }]
const DeliveryButton = () => {
const [active, setActive] = useState(false);
return deliveryChoice.map((data, k) => (
<div
key={k}
className={`deliveryChoice ${active === k ?
classes.deliveryAction : ''}`}
onClick={() => setActive(k)}
>
{data.name}
</div>
));
};
And CSS for the Button:
.deliveryChoice {
}
.deliveryAction {
background-color: #ffffff;
border-color: #ffffff;
display: flex;
font-size: 13px;
justify-content: space-around;
width: 4rem;
height: 1.8rem;
cursor: pointer;
color: rgb(0, 0, 0);
align-items: center;
border-radius: 20px;
/* padding-left: 0.5rem; */
}
I have this component that shows the full detail of my product in my e-commerce app, every time I open a different product I get this error in my console, this is the error,
Uncaught (in promise) Error: Element is probably not rendered to the DOM - something with your layout or CSS definition
at e.<anonymous> (index.tsx:197)
at index.esm.js:516
at Object.next (index.esm.js:516)
at s (index.esm.js:516)
I don't know how can I find where the Uncaught promise is.
I'm using React.js with redux-thunk to manage states, and React router also CSS modules for the CSS part as you see.
this is my component
class FullProduct extends Component {
state = {
purchasing: false,
favIcon: this.props.isFavourite,
isFavourite: this.props.isFavourite,
show: false,
isRemove: null,
showFedback: false,
isBasketAdd: false,
showBasketFedback: false
};
// get product data
loadData = () => {
if (this.props.match.params.id) {
if (
!this.props.product ||
(this.props.product &&
this.props.product.pid !== this.props.match.params.id)
) {
this.props.onGetFullProduct(this.props.match.params.id);
}
}
};
// get isFavourite info
getData = async () => {
db.collection("userFavourites")
.doc(this.props.user.uid)
.get()
.then(res => {
let favourites = res.data();
const isFavourite = favourites
? favourites[this.props.match.params.id]
: false;
if (isMount) {
this.setState({ isFavourite: isFavourite, favIcon: isFavourite });
}
})
.catch(err => {
if (isMount) this.setState({ error: err });
});
};
componentDidMount() {
isMount = true;
if (isMount) {
if (this.props.user) {
this.getData();
}
this.loadData();
}
}
componentWillUnmount() {
isMount = false;
}
componentDidUpdate() {
if (isMount) {
this.loadData();
}
}
discountHandler = (price, discount) => {
let newPrice = price - (price * discount) / 100;
return Math.round(newPrice * 100) / 100;
};
purchaseHandler = () => {
if (isMount) this.setState({ purchasing: true });
};
purchaseCancelledHandler = () => {
if (isMount) this.setState({ purchasing: false });
};
purchaseContinuedHandler = () => {
this.props.onCheckPurchasing();
if (this.props.user) {
this.props.history.push("/checkout");
}
};
loginBtnClicked = () => {
this.props.history.push("/login");
this.props.onCheckPurchasing();
};
registerBtnClicked = () => {
this.props.history.push("/register");
this.props.onCheckPurchasing();
};
onMouseEnterHandler = e => {
let fav = this.state.isFavourite;
fav = !fav;
if (isMount)
this.setState({
favIcon: fav
});
};
onMouseLeaveHandler = () => {
let fav = this.state.isFavourite;
if (isMount) this.setState({ favIcon: fav });
};
favBtnHandler = productId => {
if (this.props.user) {
let isFavourite = this.state.isFavourite;
if (isFavourite && isMount) {
this.setState({ isRemove: true });
} else {
this.setState({ isRemove: false });
}
if (isMount) this.setState({ isFavourite: !isFavourite });
db.collection("userFavourites")
.doc(this.props.user.uid)
.update({
[productId]: !isFavourite
})
.then(res => {
if (isMount) this.setState({ show: true });
setTimeout(() => {
if (isMount) this.setState({ show: false });
}, 5000);
})
.catch(err => {
let error = err.message.slice(0, 21);
if (error === "No document to update") {
db.collection("userFavourites")
.doc(this.props.user.uid)
.set({
[productId]: !isFavourite
})
.catch(err => {
if (isMount) this.setState({ error: err });
});
}
});
} else {
if (isMount) this.setState({ showFedback: true });
setTimeout(() => {
if (isMount) this.setState({ showFedback: false });
}, 5000);
}
};
loginClickedHandler = () => {
this.props.history.push("/login");
};
cancelClickedHandler = () => {
if (isMount) this.setState({ showFedback: false });
};
addToBasketHandler = () => {
let productId = this.props.product.pid;
let basketProductIds = [];
this.props.basketProducts.forEach(product =>
basketProductIds.push(product.pid)
);
let index = basketProductIds.findIndex(element => element === productId);
if (index === -1) {
this.props.onAddProductToBasket(this.props.product);
if (isMount)
this.setState({ isBasketAdd: true, showBasketFedback: true });
} else {
this.props.onRemoveProductFromBasket(this.props.product);
if (isMount)
this.setState({ isBasketAdd: false, showBasketFedback: true });
}
setTimeout(() => {
if (isMount) this.setState({ showBasketFedback: false });
}, 5000);
};
render() {
// get product image links
if (this.props.loaded) {
let images = this.props.product.images
.map(link => {
return link.match("/products/");
})
.map(link => {
const newlink = link.input.slice(link.index);
const newlink2 = newlink.slice(0, -4);
return { publicId: newlink2 };
});
// create gallery widget
const myWidget = window.cloudinary.galleryWidget({
cloudName: "e-bazaar",
container: "#my-gallery",
mediaAssets: images,
displayProps: {
mode: "classic"
},
transition: "slide",
themeProps: {
active: "#49c58f"
},
aspectRatio: "square",
zoomProps: {
trigger: "click"
},
carouselLocation: "left",
carouselStyle: "indicators",
indicatorProps: {
shape: "round"
}
});
myWidget.render();
}
// detail widget
let priceSection = null;
if (this.props.product) {
price = Math.round(this.props.product.price * 100) / 100;
priceSection = (
<p>
<span style={{ fontWeight: "bold", color: "#393D46" }}>Price: </span>
<span className={classes.Price}> {price.toFixed(2)}$</span>
</p>
);
if (this.props.product.discount) {
newPrice = this.discountHandler(
this.props.product.price,
this.props.product.discount
);
priceSection = (
<p className={classes.priceSection}>
<span className={classes.priceLabel}>Price:</span>
<span className={classes.Discount}>{price}$</span>
<span className={classes.Price}>{newPrice.toFixed(2)}$</span>
</p>
);
}
}
let fedback = (
<div className={classes.fedback}>
{this.state.isRemove ? (
<p>
Removed From Favourites <HiOutlineEmojiSad />
</p>
) : (
<p>
Added To Favourites <HiOutlineEmojiHappy />
</p>
)}
</div>
);
let basketFedback = (
<div className={classes.basketFedback}>
{!this.state.isBasketAdd ? (
<p>
Removed From Basket <HiOutlineEmojiSad />
</p>
) : (
<p>
Added To Basket <HiOutlineEmojiHappy />
</p>
)}
</div>
);
let favIcon = null;
if (this.state.isFavourite && !this.state.favIcon) {
favIcon = (
<BsHeart
style={{ color: "#626669" }}
id="icon"
className={classes.favIcons}
/>
);
} else if (this.state.isFavourite && this.state.favIcon) {
favIcon = (
<BsHeartFill
style={{ color: "#ff5e78" }}
id="icon"
className={classes.favIcons}
/>
);
} else if (!this.state.isFavourite && this.state.favIcon) {
favIcon = (
<BsHeartFill
style={{ color: "#ff5e78" }}
id="icon"
className={classes.favIcons}
/>
);
} else if (!this.state.isFavourite && !this.state.favIcon) {
favIcon = (
<BsHeart
style={{ color: "#626669" }}
id="icon"
className={classes.favIcons}
/>
);
}
let modal = (
<div className={classes.modalFedback}>
<p>
You have to login to your account, in order to add product to your
wishlist <HiOutlineEmojiHappy />
</p>
<Button btnType="Danger" clicked={this.cancelClickedHandler}>
CANCEL
</Button>
<Button btnType="Success" clicked={this.loginClickedHandler}>
LOGIN
</Button>
</div>
);
let detail = null;
if (this.props.product) {
detail = (
<div className={classes.detail}>
<h1 className={classes.title}>{this.props.product.title}</h1>
<p className={classes.desc}>{this.props.product.description}</p>
<p className={classes.brand}>
<span style={{ fontWeight: "bold", paddingRight: "10px" }}>
Brand:
</span>
{this.props.product.brand}
</p>
<p className={classes.amount}>
<span style={{ fontWeight: "bold", paddingRight: "10px" }}>
Amount:
</span>
{this.props.product.amount}
<span style={{ paddingLeft: "5px" }}></span>
available
</p>
{priceSection}
<div className={classes.ReviewSection}>
<Rating rating={this.props.product.rating} />
</div>
<div className={classes.MenuIcons}>
<span
className={classes.iconDiv}
onMouseEnter={e => this.onMouseEnterHandler(e)}
onMouseLeave={this.onMouseLeaveHandler}
onClick={() => this.favBtnHandler(this.props.match.params.id)}
>
{favIcon}
</span>
<span className={classes.iconDiv} onClick={this.addToBasketHandler}>
<Icon src={basket1} src2={basket2} />
</span>
<Button btnType="Primary" clicked={this.purchaseHandler}>
<FaShoppingCart /> SHOP NOW
</Button>
</div>
</div>
);
}
const screen = !this.props.loading ? (
<Aux>
<div id="my-gallery" className={classes.Gallery}></div>
{detail}
</Aux>
) : (
<Spinner />
);
let orderSummary = null;
if (this.props.product) {
orderSummary = (
<OrderSummary
product={this.props.product}
price={this.props.product.discount ? newPrice : price}
purchaseCancelled={this.purchaseCancelledHandler}
purchaseContinued={this.purchaseContinuedHandler}
/>
);
}
if (!this.props.user) {
orderSummary = (
<div>
<p className={classes.happyIcon}>
<HiOutlineEmojiHappy />
</p>
<p className={classes.noUserWarning}>
You have to login or create an account to complete your order...
</p>
<div className={classes.awayBtn}>
<Button btnType="Success" clicked={this.loginBtnClicked}>
LOGIN
</Button>
</div>
<div className={classes.awayBtn}>
<Button
btnType="Success"
clicked={this.registerBtnClicked}
className={classes.awayBtn}
>
REGISTER
</Button>
</div>
</div>
);
}
return (
<Aux>
<Modal
show={this.state.showFedback}
ModalClosed={this.cancelClickedHandler}
>
{modal}
</Modal>
{this.props.noProduct ? (
<NotFound />
) : (
<Aux>
<div className={classes.FullProduct}> {screen} </div>
<Modal
show={this.state.purchasing}
ModalClosed={this.purchaseCancelledHandler}
>
{orderSummary}
</Modal>
</Aux>
)}
{this.state.show ? fedback : null}
{this.state.showBasketFedback ? basketFedback : null}
</Aux>
);
}
}
const mapStateToProps = state => {
return {
productId: state.products.productId,
product: state.fullProduct.product,
loading: state.fullProduct.loading,
loaded: state.fullProduct.loaded,
error: state.fullProduct.error,
noProduct: state.fullProduct.noProduct,
user: state.auth.user,
isFavourite: state.products.isFavourite,
basketProducts: state.fullProduct.basketProducts
};
};
const mapActionsToProps = dispatch => {
return {
onGetFullProduct: id => dispatch(actions.getFullProduct(id)),
onCheckPurchasing: () => dispatch(actions.checkPurchasing()),
onAddProductToBasket: product =>
dispatch(actions.addProductsToBasket(product)),
onRemoveProductFromBasket: product =>
dispatch(actions.removeProductsFromBasket(product))
};
};
export default connect(
mapStateToProps,
mapActionsToProps
)(withRouter(FullProduct));
CSS of the component:
.FullProduct {
margin-top: 150px;
padding: 50px 10px 20px 10px;
display: flex;
align-items: flex-start;
flex-direction: row;
justify-content: center;
flex-wrap: wrap;
column-gap: 30px;
row-gap: 30px;
overflow: hidden;
}
.Gallery {
width: 35%;
padding: 20px;
border-radius: 10px;
box-shadow: rgba(36, 37, 38, 0.08) 0px 6px 15px 0px;
transition: all 0.3s cubic-bezier(.25, .8, .25, 1);
border: 1px solid white;
background-color: white;
margin: 0px 10px 20px 10px;
}
.detail {
width: 40%;
padding: 20px;
border-radius: 10px;
box-shadow: rgba(36, 37, 38, 0.08) 0px 6px 15px 0px;
transition: all 0.3s cubic-bezier(.25, .8, .25, 1);
border: 1px solid white;
background-color: white;
margin: 0 0 20px 0;
}
.title {
color: #393D46;
font-size: 3rem;
}
.desc {
color: #9fa4af;
text-align: left;
white-space: pre-wrap;
}
.brand {
color: #393D46;
}
.amount {
color: #393D46;
}
.priceLabel {
font-weight: bold;
color: #393D46;
padding-right: 10px;
}
.Price {
font-size: 2.5rem;
color: #45C48B;
margin: 20px 7px;
}
.Discount {
font-size: 1.8rem;
color: #9ba5af;
text-decoration: line-through;
text-decoration-color: #172B4D;
text-decoration-thickness: 3px;
}
.ReviewSection {
margin: 20px 0;
}
.iconDiv {
display: inline-block;
position: relative;
top: 10px;
}
.fedback {
background: #ff5e78;
padding: 0px 5px;
border-radius: 10px;
position: fixed;
z-index: 80;
right: 25px;
bottom: 50px;
}
.fedback>p {
color: white;
margin: 10px 5px;
font-size: large;
}
.basketFedback {
background: #45C48B;
padding: 0px 5px;
border-radius: 10px;
position: fixed;
z-index: 80;
right: 25px;
bottom: 50px;
}
.basketFedback>p {
color: black;
margin: 10px 5px;
font-size: large;
}
.modalFedback {
background: white;
padding-bottom: 20px;
}
.modalFedback>p {
font-size: larger;
margin-bottom: 40px;
}
.favIcons {
font-size: 30px;
padding-right: 10px;
}
.iconDiv img {
display: inline-block;
padding-right: 10px;
width: 30px;
height: 30px;
}
.noUserWarning {
margin: 40px 20px;
}
.happyIcon {
font-size: xx-large;
color: #393D46
}
.awayBtn {
display: inline-block;
}
#media(max-width:730px) {
.detail {
width: 80%;
}
.Gallery {
width: 80%;
}
}
#media(max-width:389px) {
.priceLabel {
display: block;
}
.Discount {
display: block;
}
.Price {
display: block;
}
}
#media(max-width:280px) {
.iconDiv {
top: -10px;
}
.awayBtn {
margin: 10px 0;
}
}
I'm following this react-flip-toolkit tutorial in order to animate a<div> expansion in a component:
This is the tutorial code:
import React, { useState } from 'react'
import { Flipper, Flipped } from 'react-flip-toolkit'
const AnimatedSquare = () => {
const [fullScreen, setFullScreen] = useState(false)
const toggleFullScreen = () => setFullScreen(prevState => !prevState)
return (
<Flipper flipKey={fullScreen}>
<Flipped flipId="square">
<div
className={fullScreen ? 'full-screen-square' : 'square'}
onClick={toggleFullScreen}
/>
</Flipped>
</Flipper>
)
}
My project however, unlike the functional Component example above, uses Class components, like so:
class Field extends Component {
constructor(props) {
super(props);
this.state = {
players:[],
};
}
getPlayersByPosition = (players, position) => {
return players.filter((player) => player.position === position);
};
render() {
const { players } = this.props;
if(players){
return (
<div className="back">
<div className="field-wrapper" >
<Output output={this.props.strategy} />
// this is the target div I want to expand
<div className="row">
{this.getPlayersByPosition(players, 5).map((player,i) => (
<Position key={i} >{player.name}</Position>
))}
</div>
</div>
</div>
);
}else{
return null}
}
}
export default Field;
How can I declare AnimatedSquare() in my Class component and encapsulate my target <div> above within <Flipper/> and <Flipped/>?
I've converted the example to a class based component for you. You should be able to work the rest out from this example:
import React, { Component } from "react";
import ReactDOM from "react-dom";
import { Flipped, Flipper } from "react-flip-toolkit";
import "./styles.css";
class AnimatedSquare extends Component {
state = {
fullScreen: false
};
toggleFullScreen() {
this.setState({ fullScreen: !this.state.fullScreen });
}
render() {
const { fullScreen } = this.state;
return (
<Flipper flipKey={fullScreen}>
<Flipped flipId="square">
<div
className={fullScreen ? "full-screen-square" : "square"}
onClick={this.toggleFullScreen.bind(this)}
/>
</Flipped>
</Flipper>
);
}
}
ReactDOM.render(<AnimatedSquare />, document.querySelector("#root"));
* {
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.square {
width: 5rem;
height: 5rem;
cursor: pointer;
background-image: linear-gradient(
45deg,
rgb(121, 113, 234),
rgb(97, 71, 182)
);
}
.full-screen-square {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: pointer;
background-image: linear-gradient(
45deg,
rgb(121, 113, 234),
rgb(97, 71, 182)
);
}
I have a some popup block or modal window as you like. And I want that it will close after I press on button. Button will be visible after checkboox will be true. Help me pls. May be I have to add something to css, or JS code is incorrect.
Code is below.
class ModalWindow extends React.Component {
constructor() {
super();
this.state = {
open: false,
checked: false
};
this.handleChange = this.handleChange.bind(this);
}
handleChange() {
this.setState({
checked: !this.state.checked
})
}
hide() {
this.setState({
open: false,
});
}
show() {
this.setState({
open: true,
});
}
componentDidMount() {
this.show();
}
render() {
const buttonContent = this.state.checked ? <div className={s.showButton}>
<button onClick={() => this.hide()} className={s.closeBtn}>Confirm yes yes</button>
</div> : null;
return (
<div className={this.state.open ? 'show':'hide'}>
<div className={s.modal}>
<h2 className={s.modalText}>Some text in block</h2>
<label>I want to confirm</label>
<input type="checkbox" checked={this.state.checked} onChange={this.handleChange}/>
{buttonContent}
</div>
</div>
);
}
}
export default withStyles(s)(ModalWindow);
.modal {
background:#fff;
width: 350px;
height: 200px;
margin: 5% auto;
padding: 5px 20px;
position: relative;
border: 2px solid #0000ee;
}
.hide {
display:none
}
.modalText {
font-size: 18px;
color: #000000;
}
label {
margin:0 15px 0 0;
}
.closeBtn {
display: block;
position: absolute;
bottom: 5px;
width: 150px;
height:50px;
margin:0 0 0 100px;
outline: none;
color: #555;
border: none;
background: #000000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react-dom.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
With react you have another way to do hiding and showing of elements. You just render it or you don't.
So instead of setting the state inside the modal dialog to show or hide the modal dialog you should have a property outside of it which decides if this dialog is rendered. Your React App should look something like this:
class ComponentWithModalDialog extends React.Component {
render() {
const {showModal} = this.props;
if(showModal) {
return <ModalWindow />
}
else {
return <div>
other content
</div>
}
}
}