How to change component that is rendered? - javascript

I'm super new to React.js. I'm making changeable layouts using React.js. so i tried to use useState for rendering specific layout that I should click. so I tried to add setState for changing false in a function and made one another setState in the same function. but Too many re-renders Error came out. so what can i use for making changeable layout??
this is my code
import React, { useState } from "react";
import Panel from "./Panel";
import PanelTwo from "./PanelTwo";
import styled from "styled-components";
export default function Layout() {
const [showPanel, setShowPanel] = useState(false);
const [showPanel1, setShowPanel1] = useState(false);
const handleOnClick = () => setShowPanel(true);
const handleOnClick1 = () => setShowPanel1(true);
return (
<div>
<Main>
<div onClick={handleOnClick}>
<h1>Panel (1+3)</h1>
</div>
<div onClick={handleOnClick1}>
<h1>Panel (2+2) </h1>
</div>
<div>
<h1>Panel (2+3)</h1>
</div>
<div>
<h1>Panel (2+4)</h1>
</div>
<div>
<h1>Panel (3+1)</h1>
</div>
<div>
<h1>Panel (3+2)</h1>
</div>
</Main>
{showPanel ? <Panel /> : null}
{showPanel1 ? <PanelTwo /> : null}
</div>
);
}
and if i do this, it looks like this when i click two buttons
enter image description here
so i tried this .
const [showPanel, setShowPanel] = useState(false);
const [showPanel1, setShowPanel1] = useState(false);
const handleOnClick = () => setShowPanel(true);
const handleOnClick1 = () => setShowPanel(false);
setShowPanel1(true);
and i got Too many re-renders Error.
this is what i want to do
enter image description here
when i click each buttons then the exact only one layout is gonna show up .
but the problem is that it's overlapped when i click two buttons
like this
enter image description here
I'm sorry if my explanation is not good.

It seems like you really just want to toggle between the two layouts. You can do this with a single state value, callback, and conditional render via ternary.
export default function Layout() {
const [showPanel, setShowPanel] = useState(false);
const handleOnClick = () => setShowPanel(show => !show);
return (
<div>
<Main>
<div onClick={handleOnClick}>
<h1>Panel (1+3)</h1>
</div>
<div onClick={handleOnClick}>
<h1>Panel (2+2) </h1>
</div>
...
</Main>
{showPanel ? <Panel /> : <PanelTwo />}
</div>
);
}
OFC, this assumes you want to always show at least one of the layouts. If you want to start with both initially hidden (i.e. false) then you can toggle the other panel state false in the handlers to do that.
export default function Layout() {
const [showPanel, setShowPanel] = useState(false);
const [showPanel1, setShowPanel1] = useState(false);
const handleOnClick = () => {
setShowPanel(true);
setShowPanel1(false);
};
const handleOnClick1 = () => {
setShowPanel(false);
setShowPanel1(true);
};
return (
<div>
<Main>
<div onClick={handleOnClick}>
<h1>Panel (1+3)</h1>
</div>
<div onClick={handleOnClick1}>
<h1>Panel (2+2) </h1>
</div>
...
</Main>
{showPanel && <Panel />}
{showPanel1 && <PanelTwo />}
</div>
);
}

Related

How can I dynamically update className with React js?

I have a Collection component and when I click on a div in this component, I want to change both the className of the Collection component and the className of the first sibling component after the Collection component.
With UseState, I could only change the className of the component I was in.
My Collection.js looks like this:
const Collection = () => {
const [toggleClass, setToggleClass] = useState(false);
function handleClick() {
setToggleClass((toggleClass) => !toggleClass);
}
let toggleClassCheck = toggleClass ? "passive" : "active";
return (
<React.Fragment>
<div className={`step ${toggleClassCheck}`}>
<div className="atrium">
<span>Collection</span>
</div>
<div className="content">
<div
className="moreThenOne"
area="collectionTitle"
onClick={handleClick}
>
Can anyone help me on how to do the process I mentioned above?
I didn't quite understand what you want, but if you want to impact sibling of component "Collection" executing function inside of "Collection" you definitely should try "ref". Via useRef hook.
export const Collection = () => {
const [toggleClass, setToggleClass] = useState(false);
const divRef = useRef(null);
function handleClick() {
divRef.current.nextSibling.classList.toggle('active');
divRef.current.nextSibling.classList.toggle('passive');
setToggleClass((toggleClass) => !toggleClass);
}
let toggleClassCheck = toggleClass ? 'passive' : 'active';
return (
<>
<div className={`step ${toggleClassCheck}`} ref={divRef}>
<div className="atrium">
<span>Collection</span>
</div>
<div className="content">
<div className="moreThenOne" onClick={handleClick}>
CLICK ZONE
</div>
</div>
</div>
</>
);
};
The React components rerender, based on the state. So you sould use your state to define the className instead of a boolean.
When your state changes the component will re-render.
Try this:
const Collection = () => {
const [toggleClass, setToggleClass] = useState("active");
function handleClick() {
setToggleClass((prevState) => prevState == "active" ? "passive" : "active" );
}
return (
<React.Fragment>
<div className={`step ${toggleClass}`}>
<div className="atrium">
<span>Collection</span>
</div>
<div className="content">
<div
className="moreThenOne"
area="collectionTitle"
onClick={handleClick}
>

Create and download image of a react component without rendering it

My use case is simple. I have a react component that takes some props and renders something. Now I want to download it as an image without rendering it basically not showing it to the user.
I have tried html2canvas and react-component-export-image. In both of these libraries, I managed to capture the screenshot but both of them required me to render the component.
I used code from this page for react-component-export-image https://www.npmjs.com/package/react-component-export-image
Suppose the following is my component
const Component1 = ({ reference }) => {
return (
<div ref={reference} >
<div className="share-cause-header">
Some header stuff
</div>
<div className="share-cause-body">
some body stuff
</div>
<div className="share-cause-footer">
some footer stuff
</div>
</div>
);
};
Now on another Component2, I want to send some props to my Component1 and then download that component as an image without showing anything to the user. A user should only see the download button and the downloaded image
const Component2 = () => {
const shareButtonImageDownload = (e) => {
e.stopPropagation();
console.log("Hi there");
};
return (
<div >
<button onClick={shareButtonImageDownload } ></button>
</div>
);
};
If the component is not visible, then you can't take a screenshot of it. But you can bring them out of the visible view, like this:
https://codesandbox.io/embed/laughing-http-w3ndr?fontsize=14&hidenavigation=1&theme=dark
import {
exportComponentAsJPEG,
exportComponentAsPDF,
exportComponentAsPNG
} from "react-component-export-image";
import React, { useRef } from "react";
const ComponentToPrint = React.forwardRef((props, ref) => (
<div ref={ref} style={{ marginTop: "-50px" }}>
<div className="share-cause-header">Some header stuff</div>
<div className="share-cause-body">some body stuff</div>
<div className="share-cause-footer">some footer stuff</div>
</div>
));
const MyComponent = () => {
const componentRef = useRef();
return (
<React.Fragment>
<ComponentToPrint ref={componentRef} />
<button onClick={() => exportComponentAsJPEG(componentRef)}>
Export As JPEG
</button>
<button onClick={() => exportComponentAsPDF(componentRef)}>
Export As PDF
</button>
<button onClick={() => exportComponentAsPNG(componentRef)}>
Export As PNG
</button>
</React.Fragment>
);
};
export default MyComponent;

React useEffect Problems

So here is the problem which I can't seem to solve. I have an app component, inside of App I have rendered the Show Component. Show component has toggle functionality as well as a outside Click Logic. In the Show component I have a Button which removes an item based on his Id, problem is that When I click on the button Remove. It removes the item but it also closes the Show Component, I don't want that, I want when I press on button it removes the item but does not close the component. Thanks
App.js
const App =()=>{
const[isShowlOpen, setIsShowOpen]=React.useState(false)
const Show = useRef(null)
function openShow(){
setIsShowOpen(true)
}
function closeShowl(){
setIsShowOpen(false)
}
const handleShow =(e)=>{
if(show.current&& !showl.current.contains(e.target)){
closeShow()
}
}
useEffect(()=>{
document.addEventListener('click',handleShow)
return () =>{
document.removeEventListener('click', handleShow)
}
},[])
return (
<div>
<div ref={show}>
<img className='taskbar__iconsRight' onClick={() =>
setIsShowOpen(!isShowOpen)}
src="https://winaero.com/blog/wp-content/uploads/2017/07/Control-
-icon.png"/>
{isShowOpen ? <Show closeShow={closeShow} />: null}
</div>
)
}
Show Component
import React, { useContext } from 'react'
import './Show.css'
import { useGlobalContext } from '../../context'
import WindowsIcons from '../../WindowsIcons/WindowsIcons'
import { GrClose } from 'react-icons/gr'
const Show = ({closeShow}) => {
const {remove, icons }= useGlobalContext()
}
return (
<div className='control__Panel'>
<div className='close__cont'>
<GrClose className='close' onClick={closeShow} />
<h3>Show</h3>
</div>
<div className='control__cont'>
{icons.map((unin)=>{
const { name, img, id} = unin
return (
<li className='control' key ={id}>
<div className='img__text'>
<img className='control__Img' src={img} />
<h4 className='control__name'>{name}</h4>
</div>
<button className='unin__button' onClick={() => remove(id)} >remove</button>
</li> )
})}
</div>
</div>
)
}
export default Show
Try stop propagation function, it should stop the propagation of the click event
<button
className='unin__button'
onClick={(e) => {
e.stopPropagation();
remove(id);
}}
>remove</button>
You have a few typos in your example. Are they in your code? If they are, you're always reach the closeShow() case in your handler, since you're using the wrong ref.
const App =()=>{
const[isShowOpen, setIsShowOpen]=React.useState(false) <<-- Here 'isShowlOpen'
const show = useRef(null) <<-- here 'S'how
function openShow(){
setIsShowOpen(true)
}
function closeShow(){ <<-- Here 'closeShowl'
setIsShowOpen(false)
}
const handleShow =(e)=>{
if(show.current&& !show.current.contains(e.target)){ <<-- here 'showl'
closeShow()
}
}
useEffect(()=>{
document.addEventListener('click',handleShow)
return () =>{
document.removeEventListener('click', handleShow)
}
},[])
return (
<div>
<div ref={show}>
<img className='taskbar__iconsRight' onClick={() =>
setIsShowOpen(!isShowOpen)}
src="https://winaero.com/blog/wp-content/uploads/2017/07/Control-
-icon.png"/>
{isShowOpen ? <Show closeShow={closeShow} />: null}
</div>
)
}

useState passed to useContext not updating state

I am trying to use useContext to create a generic Tooltip component that passes a close() function to the content inside the Tooltip. I have written my Tooltip like this
export function Tooltip(props) {
const [active, setActive] = useState(false);
const close = () => {
setActive(false);
}
return (
<div className="tooltip-wrapper"
onClick={() => setActive(true)}
>
{props.children}
<TooltipContext.Provider value={{close}}>
{active && (
<div className='tooltip-tip bottom' ref={node}>
{props.content}
</div>
)}
</TooltipContext.Provider>
</div>
)
}
I create the Tooltip in a different class component as follows
function Category(props) {
return (
<Tooltip content={<AddCategoryInnerTooltip name={props.name}/>}>
<p className="tooltip-name-opener">{props.name}</p>
</Tooltip>
);
}
function AddCategoryInnerTooltip(props) {
const {close} = useContext(TooltipContext);
return(
<div className="inner-tooltip-wrapper">
<input
className="tooltip-custom-input"
type="text"
defaultValue={props.name}
/>
<div className="button-end">
<button onClick={close}>Cancel</button>
<button>Ok</button>
</div>
</div>
)
}
When I attempt to call close within the AddCategoryInnerTooltip, the state passed from the Tooltip component doesn't update. When I console.log the state, it always comes as true without changing. What am I doing wrong?
should be a callback function
<button onClick={()=>close}>Cancel</button>

Wrong pass prop in react component

I have simple Reactjs app that includes the Card and Modal components. every Card must have a Modal that when clicking on "Show More" button, open it.
Modal should only show the title on its Card and my problem is passed props to Modal, just send the title of the last Card And not about itself!
In summary, the prop of title received properly in Card component but Card component can't pass title to Modal correctly.
Here is my app in CodeSandBox: Demo
Card Components:
const Card = props => {
const { children, title } = props;
const { isShowModal, setIsShowModal } = useContext(MainContext);
const showModalHandler = () => {
setIsShowModal(true);
};
return (
<div className="card">
<div className="card-header">
<h2>{title}</h2>
</div>
<div className="card-content">{children}</div>
<div className="card-footer">
<button onClick={showModalHandler}>Show More</button>
</div>
{isShowModal && <Modal title={title} />}
</div>
);
};
Modal Component:
const Modal = props => {
const { setIsShowModal } = useContext(MainContext);
const closeModalHandler = () => {
setIsShowModal(false);
};
const { title } = props;
return (
<div className="modal">
<h2>Modal: {title}</h2>
<p>
You cliked on <b>{title}</b> Card
</p>
<hr />
<button onClick={closeModalHandler}>Close</button>
</div>
);
};
Note: I use Context for control open/close modal in isShowModal state and maybe that's the problem?
Just as you thought the problem seems to be the useContext that you are using. So I made a couple of changes to the code, most importantly using useState. I recommend you read the documentation about useContext and when to use it. Here is the updated code:
Card.js
import React, { useState } from "react";
import Modal from "./Modal";
import "./Card.scss";
const Card = props => {
const { children, title } = props;
const [ isShowModal, setIsShowModal ] = useState(false);
return (
<div className="card">
<div className="card-header">
<h2>{title}</h2>
</div>
<div className="card-content">{children}</div>
<div className="card-footer">
<button onClick={() => setIsShowModal(true)}>Show More</button>
</div>
{isShowModal && <Modal setIsShowModal={setIsShowModal} title={title} />}
</div>
);
};
export default Card;
Modal.js
import React from "react";
import "./Modal.scss";
const Modal = props => {
const { title } = props;
return (
<div className="modal">
<h2>Modal: {title}</h2>
<p>
You cliked on <b>{title}</b> Card
</p>
<hr />
<button onClick={() => props.setIsShowModal(false)}>Close</button>
</div>
);
};
export default Modal;
As you can see, Modal.js component doesn't have to be a stateful component. You can pass as a prop the setIsShowModal function from Card.js component. That way you can make the modal a reusable component.

Categories

Resources