React hooks - set state of Parent from child via function - javascript

guys I am just learning React and I decide to do try to build Hero Database and I encounter a problem.
When I click on any of Heroes, Bio state and Display state updates with data about the hero and modal window pop up with more information about him. But I don't know how to close it. I have Modal as a separate component and when I am trying calling the function (updateDisplay) from child component. which should set State of Display to False it just doesn't work :/
Heroes.js
import React, { useState } from "react";
import Hero from "./Hero";
import styled from "styled-components";
function Heroes(props) {
const [Bio, setBio] = useState([]);
const [Display, setDisplay] = useState(false);
const SingleHeroCont = styled.div`
display: flex;
flex-direction: column;
margin-top: 10px;
padding: 10px;
align-items: center;
`;
const content = props.data.map((Hero) => (
<SingleHeroCont
onClick={() => {
setBio(Hero);
setDisplay(true);
}}
key={Hero.id}
>
<h1>{Hero.name}</h1>
<img src={Hero.images.sm} alt="Sorry guys"></img>
</SingleHeroCont>
));
const updateDisplay = () => {
setDisplay(false);
};
return (
<div className="heroes_cont">
<Hero updateDisplay={updateDisplay} Display={Display} BioData={Bio} />
{content}
</div>
);
}
export default Heroes;
Hero.js
import React from "react";
import styled from "styled-components";
function Hero({ Display, updateDisplay, BioData }) {
const HeroAbsolute = styled.div`
display: ${(props) => (props.showBio ? "block" : "none")};
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 255, 255, 0.5);
`;
return (
<HeroAbsolute showBio={Display}>
<div className="hero_bio_cont">
<h1>{BioData.name}</h1>
<button onClick={() => updateDisplay}>Close</button>
<div className="hero_bio_appearance">
<div>
<img></img>
<div>
<h2>{BioData.powerstats?.power}</h2>
<h2></h2>
<h2></h2>
</div>
</div>
</div>
</div>
</HeroAbsolute>
);
}
export default Hero;

<button onClick={() => updateDisplay}>Close</button>
As I see, the above code is not working to call updateDisplay function.
Correct usage would be
<button onClick={() => updateDisplay()}>Close</button>
Or
<button onClick={updateDisplay}>Close</button>
Please refer to the arrow function tutorial for the second case.

Related

I created a Modal using createPortal() method to render it. Then I found that modal renders twice

When the button inside the Post clicked, Popup will render with createPortal method outside from root element's tree.
With this code that popup renders twice.
I want to render it only once.
Here's the parent Post component.
import { useState } from 'react';
import PopupModal from './PopupModal/PopupModal';
import './Post.css';
const Post = (props) => {
const postData = props;
const [isOpen, setIsOpen] = useState(false);
return (
<div className="post-container">
<div className="post-img-container">
<img className="post-img" src={props.img} alt="Travels" />
</div>
<div className="post-text-container">
<h4 className="post-heading">{props.title}</h4>
<p className="post-para">{props.description}</p>
<h1 className="post-price">{props.price}</h1>
<div className="post-btn-container">
<button onClick={() => setIsOpen(true)} className="post-btn">
Check Availability
</button>
<PopupModal dataData={postData} open={isOpen} onClose={() => setIsOpen(false)}>
Button123
</PopupModal>
</div>
</div>
</div>
);
};
export default Post;
And here's the popupModal
import React from 'react';
import ReactDOM from 'react-dom';
import '../PopupModal/popupModal.css'
const MODAL_STYLES = {
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%,-50%)',
background: '#fff',
width: '40vw',
height: '90vh',
padding: '50px',
zIndex: 1000,
};
const PopupModal = ({ open, children, onClose ,dataData }) => {
if (!open) return null;
console.log('xxx');
console.log(dataData);
return ReactDOM.createPortal(
<>
<div className='modal-overlay' ></div>
<div className='modal-container'>
<button onClick={onClose}> Popup Close</button>
{children}
</div>
</>,
document.getElementById('portal')
);
};
export default PopupModal;
Here's how I figured it rendered twice.
Here's the Popup with overlay around it which covers the background.
Thanks in advance!
Try following
{
isOpen && <PopupModal dataData={postData} open={isOpen} onClose={() => setIsOpen(false)}>
Button123
</PopupModal>
}

making antd modal full screen without any padding or margins

I'm new to programming. Here I have an antd modal and I've been trying to find a way to make it full screen. I want the modal to be full scree when it's opened and it shouldn't have any margin or paddings. For example, in the code I added width={1000} but there is still some margin on the left and right of the modal.
So how do I make the modal to take the whole screen without any margin and padding?
code:
https://codesandbox.io/s/otjy6?file=/index.js:539-560
Remove the fixed value for modal width and the centered attribute from your code file:
index.js
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Modal, Button } from 'antd';
const App = () => {
const [visible, setVisible] = useState(false);
return (
<>
<Button type="primary" onClick={() => setVisible(true)}>
Open Modal of 1000px width
</Button>
<Modal
title="Modal 1000px width"
// This was removed
// centered
visible={visible}
onOk={() => setVisible(false)}
onCancel={() => setVisible(false)}
// This was removed
// width={'1000'}
>
<p>some contents...</p>
<p>some contents...</p>
<p>some contents...</p>
</Modal>
</>
);
};
ReactDOM.render(<App />, document.getElementById('container'));
You need to add these CSS rules to the CSS file.
index.css
.ant-modal, .ant-modal-content {
height: 100vh;
width: 100vw;
margin: 0;
top: 0;
}
.ant-modal-body {
height: calc(100vh - 110px);
}
you need to unset max-width and margin of modal
.ant-modal {
max-width: unset;
margin: unset;
}
you need to unset content in before pseudo-element of ant-modal-centered class
.ant-modal-centered::before {
content: unset;
}
Working Demo
I think instead of Modal you can use the Antd Drawer. Here is the implementation.
import React,{useState} from 'react';
import {Drawer} from 'antd;
const FullScreenDrawer = ()=>{
const [visible,setVisible] = useState(false)
return(
<>
<button onClick={()=>setVisible(true)/>
<Drawer
visible={isVisible}
onClose={() => setVisible(false)}
width="100VW"
>
The content goes here
</Drawer>
</>
);
}

ReactJS onclick add or remove class to another element

I am struggling to convert my normal jQuery code in to React JS (I'm new to React).
I have the following code:
$(".add").click(function () {
$("nav").addClass("show");
});
$(".remove").click(function () {
$("nav").removeClass("show");
});
$(".toggle").click(function () {
$("nav").toggleClass("show");
});
nav {
width: 250px;
height: 150px;
background: #eee;
padding: 15px;
margin-top: 15px;
}
nav.show {
background: red;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<button class="add">Add</button>
<button class="remove">Remove</button>
<button class="toggle">Toggle</button>
<nav>Navigation menu</nav>
Tried references seems that only add/remove class for the same element:
https://stackoverflow.com/a/42630743/6191987
How to add or remove a className on event in ReactJS?
So, how can I convert or create the same jQuery methods to ReactJS?
Use the state that keeps the track of whether to show the nav or not.
Use a class name in the react code that corresponds to the state.
React uses "className" instead of "class" since "class" is already a reserved word in javascript.
You could check this sandbox link for implementation
function App() {
const [show, setShow] = React.useState();
return (
<div className="App">
<button className="add" onClick={() => setShow(true)}>
Add
</button>
<button className="remove" onClick={() => setShow(false)}>
Remove
</button>
<button className="toggle" onClick={() => setShow(!show)}>
Toggle
</button>
<nav className={show ? "show" : ""}>Navigation menu</nav>
</div>
);
}
You could combine the use useRef for nav and manipulate the ref (accessing nav's DOM) with event handlers for each button
import React from "react";
import "./styles.css";
export default function App() {
const navRef = React.useRef(null);
const onAddClick = (e) => {
navRef.current.classList.add("show");
};
const onRemoveClick = (e) => {
navRef.current.classList.remove("show");
};
const onToggleClick = (e) => {
navRef.current.classList.toggle("show");
};
return (
<div className="App">
<button onClick={onAddClick}>Add</button>
<button onClick={onRemoveClick}>Remove</button>
<button onClick={onToggleClick}>Toggle</button>
<nav ref={navRef}>Navigation menu</nav>
</div>
);
}
.App {
font-family: sans-serif;
}
nav {
width: 250px;
height: 150px;
background: #eee;
padding: 15px;
margin-top: 15px;
}
nav.show {
background: red;
color: white;
}
Codesanbox link for demo
Reference:
Refs and the DOM
useRef doc
Element.classList doc

How to scroll at bottom in react on button

I am trying to scroll down user at bottom when user click on button . I really tried hard but didn't find any solution . Could someone please help me how to achieve my goal .
Thanks
You can use document.body.offsetHeight to get the height of the page and scroll to it using windows.scroll. If you need to support IE11 and lower use window.scroll(0, document.body.offsetHeight);
import React from 'react';
function App() {
function handleScroll() {
window.scroll({
top: document.body.offsetHeight,
left: 0,
behavior: 'smooth',
});
}
return <button type="button" onClick={handleScroll}>Scroll</button>;
}
There are few ways to achieve this:
const onClick = () => {
window.scroll({
bottom: document.body.scrollHeight, // or document.scrollingElement || document.body
left: 0,
behavior: 'smooth'
});
}
...
return <button onClick={onClick} ... />
and another way with a ref. You need to add an element to the bottom of the page
and scroll to it after button clicked:
const bottomRef = React.useRef();
const onClick = () => {
bottomRef.current.scrollIntoView();
}
...
return (
<div className="container">
<button onClick={onClick} />
<div className="bottomContainerElement" ref={bottomRef} />
<div>
)
You install react-scroll-button npm package
npm i react-scroll-button
Usage code
import React, {Component} from 'react'
import ScrollButton from 'react-scroll-button'
class ScrollComponent extends Component {
render() {
return (
<ScrollButton
behavior={'smooth'}
buttonBackgroundColor={'red'}
iconType={'arrow-up'}
style= {{fontSize: '24px'}}
/>
);
}
}
You can use useRef hook to scrool to particular div.
This is the most recommended method by react and using react hooks.
App.js
import React, { useRef } from "react";
import "./styles.css";
export default function App() {
const divRef = useRef();
return (
<div className="App">
<button
onClick={() => {
divRef.current.scrollIntoView({ behavior: "smooth" });
}}
>
Scroll to Bottom
</button>
<div className="bigDiv" />
<div className="bigDiv" />
<div className="bigDiv" />
<div className="bigDiv" ref={divRef}>
Scrolled Here
</div>
</div>
);
}
Styles.css
.App {
font-family: sans-serif;
text-align: center;
}
.bigDiv {
height: 100vh;
width: 100%;
background: cyan;
border: 1px solid violet;
}

React.js Popup modal for shopping cart

I am currently working on a shopping cart and I am trying to figure out how to have the modal appear once I click on the shopping cart icon. I have looked at the documentation for the semantic-ui for modals but it is vague as to how to get the modal to appear when clicking on something. I am using the semantic-ui class="ui modal" for the modal.
I was thinking of putting an onClick on the icon but was still confused as to how to go from there. Currently, I have the icon in another component and the shopping cart in another separate component. I want the items to appear inside of the pop-up modal which should be the shopping cart.
import React from 'react'
import { Icon } from 'semantic-ui-react';
const ShoppingCartIcon = () => {
return(
<Icon.Group size='big' className="shopping_cart_icon">
<Icon link name='shopping cart'/>
<Icon corner='top right'/>
</Icon.Group>
)
}
export default ShoppingCartIcon;
import React from 'react'
import Shirt from './Shirt';
class ShoppingCart extends React.Component {
render() {
const listShirts = this.props.shirts.map(shirt => {
return <Shirt key={shirt.id} {...shirt}/>
})
return(
<div className="ui modal">
<div className="content">
{listShirts}
</div>
</div>
)
}
}
export default ShoppingCart;
Currently, I do not have the functionality for adding items to the cart working yet. I just want to focus on getting the modal to show up once I click on the shopping cart icon
as far as I see, you are not using neither redux nor context api. you are passing props with props drilling.
so this is how you should organize your code step by step.
we render cartIcon component in the header.js. here is a classic header
Header.js
import CartDropdown from "../cart-dropdown/cart-dropdown.component";
class Header extends React.Component {
constructor(props) {
super(props);
state = { hidden: true, cartItems:[]};
}
toggleHidden() {
this.setState(() => ({ hidden: !this.state.hidden }));
}
render() {
return (
<div className="header">
<Link className="logo-container" to="/">
<Logo className="logo" />
</Link>
<div className="options">
<Link className="option" to="/shop">
SHOP
</Link>
<Link to="/contact" className="option">
CONTACT
</Link>
{/* <Link></Link> */}
<CartIcon />
</div>
{hidden ? null : (
<CartDropdown
toggle={this.toggleHidden}
cartItems={this.state.cartItems}
></CartDropdown>
)}
</div>
);
}
}
you said you have not set the addItem functionality yet. as you add items to the cartItems array you will display them in the cart.
now we need to set up the cartDropdown component.
const CartDropdown = ({ cartItems, toggleHidden }) => (
<div className="cart-dropdown">
<div className="cart-items">
{cartItems.length ? (
cartItems.map(item => <CartItem key={item.id} item={item} />)
) : (
<span className="empty-message"> Your cart is empty </span>
)}
</div>
<CustomButton
onClick={() => {
toggleHidden();
}}
>
GO TO CHECKOUT
</CustomButton>
</div>
);
here we need to add css for cartDropdown. I do not how you are dealing with your css. prop-types or scss but here is the css code so you can apply to your project.
css for cartDropdown component
.cart-dropdown {
position: absolute;
width: 240px;
height: 340px;
display: flex;
flex-direction: column;
padding: 20px;
border: 1px solid black;
background-color: white;
top: 80px;
right: 0;
z-index: 5;
.cart-items {
height: 240px;
display: flex;
flex-direction: column;
overflow: scroll;
}
.empty-message {
font-size: 18px;
margin: 50px auto;
}
button {
margin-top: auto;
}
}

Categories

Resources