Reputation: 4769
I have multiple pages in my React app where I want to have this functionality. So in a certain React page I add CopyToClipboard
and the children
TabIcon:
<CopyToClipboard>
<TabIcon type="link" title="Test one" />
<TabIcon type="embed" title="Test two" />
</CopyToClipboard>
In another page I maybe have only:
<CopyToClipboard>
<TabIcon type="link" title="Test one" />
</CopyToClipboard>
The TabIcon
component:
const TabIcon = ({ title, type, onClick }: Props) => {
const theme = useTheme();
const styles = Styles({ theme });
return (
<li>
<ButtonBase type="button" onClick={onClick} title={title} disableRipple>
<span css={styles.icon}>{type === 'embed' ? <EmbedIcon /> : <LinkIcon />}</span>
</ButtonBase>
</li>
);
};
The CopyToClipboard
component:
const CopyToClipboard = ({ children }: Props) => {
const [isOpen, setIsOpen] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const stringToCopy =
type === 'link'
? `https://www.mysite${path}`
: `<iframe>// iframe code etc here</iframe>`;
const handleClick = () => {
setIsOpen((current) => !current);
};
return (
<div>
<ul>
{children.map((item) => (
<TabIcon type={item.type} onClick={handleClick} />
))}
</ul>
{isOpen && (
<div>
<p>{stringToCopy}</p>
<ButtonBase type="button" onClick={handleCopyClick} disableRipple>
<span>{isCopied ? `${suffix} copied` : `Copy ${suffix}`}</span>
<span>{isCopied ? <CheckIcon /> : <CopyIcon />}</span>
</ButtonBase>
</div>
)}
</div>
);
};
export default CopyToClipboard;
So what I like to achieve is the following:
div
. When clicking the other button it shows the associated content of that button. When you click that button again it hides the div.How to achieve this within my example?
Upvotes: 1
Views: 158
Reputation: 191976
You need a single state (text
). If the text
has a truthy value (actual text in this case), the div
is displayed.
When you set the text, the handleClick
compares the prevText
and the new text (txt
), and if they are equal it sets null
as the value of text
, which hides the div
. If they are not equal, the new text is set, and the div
is displayed.
const { useState } = React;
const Demo = () => {
const [text, setText] = useState(null);
const handleClick = txt => {
setText(prevText => prevText === txt ? null : txt);
};
return (
<div>
<ul>
<li>
<button onClick={() => handleClick('Button 1 text')}>
Button 1
</button>
</li>
<li>
<button onClick={() => handleClick('Button 2 text')}>
Button 2
</button>
</li>
</ul>
{text && (
<div>
<p>{text}</p>
</div>
)}
</div>
);
}
ReactDOM.createRoot(root)
.render(<Demo />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="root"></div>
Upvotes: 1