React Use State to Show Otherwise Hide

How to Show or Hide a div using useState in NextJS?

You have many HTML/CSS issues like positioning and element structure.

The free tailwindui example is a solid example to reference. It has nice transitions and accessibility baked in, which I removed for the example. It also uses headlessui and heroicons, both were built by the TW team. The TW menu components handle the state internally, so you will not be able to see the logic in their example.

The below responsive example is based on the above-referenced version but without external dependencies.

import { useState } from "react";

const Navbar = () => {
const [isOpen, setOpen] = useState(false);
const toggleMenu = () => setOpen(!isOpen);

return (
<header className="relative bg-white">
<div className="max-w-7xl mx-auto px-4 sm:px-6">
<div className="flex justify-between items-center border-b-2 border-gray-100 py-6 md:justify-start md:space-x-10">
<div className="flex justify-start lg:w-0 lg:flex-1">
<a href="#">
<span className="h-8 w-auto sm:h-10">LOGO</span>
</a>
</div>
<div className="-mr-2 -my-2 md:hidden">
<button
onClick={toggleMenu}
className="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500"
>
Open
</button>
</div>
<nav className="hidden md:flex space-x-10">
<a href="#" className="text-base font-medium text-gray-500 hover:text-gray-900">
About
</a>
</nav>
</div>
</div>
{isOpen && (
<div className="absolute top-0 inset-x-0 p-2 transition transform origin-top-right md:hidden">
<div className="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 bg-white divide-y-2 divide-gray-50">
<div className="pt-5 pb-6 px-5">
<div className="flex items-center justify-between">
<div>
<span className="h-8 w-auto">LOGO</span>
</div>
<div className="-mr-2">
<button
onClick={toggleMenu}
className="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500"
>
X
</button>
</div>
</div>
<div className="mt-6">
<nav className="grid gap-y-8">
<a href="#" className="p-3 flex items-center rounded-md hover:bg-gray-50">
About
</a>
</nav>
</div>
</div>
</div>
</div>
)}
</header>
);
};

You will also likely need to handle the closing of the menu on route change.

import { useRouter } from "next/router";
import { useEffect, useState } from "react";

const Navbar = () => {
const [isOpen, setOpen] = useState(false);
const toggleMenu = () => setOpen(!isOpen);
const router = useRouter();

useEffect(() => {
const closeMenu = () => isOpen && setOpen(false);
router.events.on("routeChangeStart", closeMenu);
return () => {
router.events.off("routeChangeStart", closeMenu);
};
}, [isOpen, router]);

return (
...see above example

how to hide and show a div in react

Typical way

The most common pattern to this is selectively rendering the element based on state.

class Foo extends React.Component {

state = { showing: true };

render() {
const { showing } = this.state;
return (
<div>
<button onClick={() => this.setState({ showing: !showing })}>toggle</button>
{ showing
? <div>This is visible</div>
: null
}
</div>
)
}
}

Alternative

You can also use a style based on state. This is less common, but can be useful when you have complex components inside that div - one recent example, I had a complex non-React D3 graph within a toggle-able component, initially, I used the first method above, but caused quite a bit of lagging when flicking the div on/off because D3 was cycling up again.

Generally use the first approach though, unless you have a reason to use the alternative.

class Foo extends React.Component {

state = { showing: true };

render() {
const { showing } = this.state;
return (
<div>
<button onClick={() => this.setState({ showing: !showing })}>toggle</button>
<div style={{ display: (showing ? 'block' : 'none') }}>This is visible</div>
</div>
)
}
}

Note

I use the ?: ternary operator instead of && - I'm a strong believer that the use of && is relying on a side effect of that operator to achieve a certain outcome. It works, don't get me wrong, but the ternary operator, in my opinion, is far more expressive and was designed to be a conditional.

This last bit is just my opinion - so I'm not questioning the use of &&.

Hide multiple divs with useState hooks React

I'm not 100% sure what you mean by a more 'generic' solution. Here is what comes to my mind:

First of all, we create a more complex object to basically hold all the variables / sections we encounter and use this as our state.

const initialVisibleAreas = {
area1: true,
area2: false
};

const [visibleAreas, setVisibleAreas] = useState(initialVisibleAreas);

Please note that this is propabably something you want to generate from your data using Object.keys(...) or mapping an array.

Next up, we create the functions for the buttons to use this new state accordingly:

  // shows the element by given key
const showInfo = (event, key) => {
event.preventDefault();
setVisibleAreas({ ...visibleAreas, ...{ [key]: true } });
};

// hides the element by given key
const hideInfo = (event, key) => {
event.preventDefault();
setVisibleAreas({ ...visibleAreas, ...{ [key]: false } });
};

// sets every key to false to hide them all at once
const hideAllInfo = (event) => {
event.preventDefault();

const allFalse = Object.assign(
...Object.keys(visibleAreas).map((key) => ({ [key]: false }))
);

setVisibleAreas(allFalse);
};

Last but not least, we use them in jsx. This is basically one 'section':

<button
onClick={(e) => {
showInfo(e, 'area2');
}}
>
Show info 2
</button>
{
visibleAreas['area2'] && (
<div className="info">
Info 2
<button
onClick={(e) => {
hideInfo(e, 'area2');
}}
>
Close
</button>
</div>
);
}

To answer the last question; nothing is holding you to call 'hideAllInfo' inside a onClick handler of your surounding div. Sample is included in the modified stackblitz.

Have a complete look at the modified stackblitz

EDIT: In the case you want to close all areas by clicking the surrounding div, make sure to not propagate the button click event with:

event.stopPropagation();

I updated the stackblitz once again.

How do I hide and show components with useState or conditional rendering in React?

If I were you, I would simplify things. First, I would extract array from the component as you don't want that to be re-rendered every time a component is re-rendered. Then, I would change your state and leave only the items state that will contain array items. I would also extend the array items by providing a flag isVisible. Then, I would remove your useEffect and improve the handleClick as you want to trigger this only when a button is clicked. In the handleClick function, I would create a new set of items by mapping through your items and changing "not clicked" items isVisible to false. This way, you know which items to hide. Lastly, I would render the components based on the isVisible attribute. So if isVisible is true, the item will be rendered with hidden set to false and vice versa.

This way the code is much simpler, more performant and easier to understand. Plus, it does what you asked.

Here's the link of the example working code: codesandbox

import React, { useState } from "react";

const Comp1 = () => <div>hi</div>;
const Comp2 = () => <div>hi2</div>;
const Comp3 = () => <div>hi3</div>;

const array = [
{ id: 1, component: <Comp1 />, isVisible: true },
{ id: 2, component: <Comp2 />, isVisible: true },
{ id: 3, component: <Comp3 />, isVisible: true }
];

export const Test = () => {
const [items, setItems] = useState(array);

const handleClick = (number) => {
const triggeredItems = items.map((item) => {
if (item.id !== number) {
item.isVisible = !item.isVisible;
}

return item;
});

setItems(triggeredItems);
};

return (
<div className="flex">
{items.map(({ id, component, isVisible }) => (
<div
key={id}
className="h-12 w-12 bg-gray-400 m-1 flex items-center justify-center"
onClick={() => handleClick(id)}
hidden={!isVisible}
>
{component}
</div>
))}
</div>
);
};

export default Test;

How to hide an element using useState and classList manipulation - React

I would do something like adding a prop which would look like this..

Small change in your LineSvg

const LineSvg = ({redLineActive}) => {


return(
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 59.6 830" xmlSpace="preserve" className="capsules capsules-image-bottom-right position-absolute">
{redLineActive ?
<path id="red-line" className="capsule-a capsule-foreground fill-red track-on-scroll" d="M10.4,257.6A10.39,10.39,0,0,1,20.8,268V584.4a10.4,10.4,0,0,1-20.8,0V267.9A10.37,10.37,0,0,1,10.4,257.6Z" />
: null }
<g className="track-on-scroll">
<path id="green-line" d="M49.2,394.7a10.39,10.39,0,0,1,10.4,10.4v84.4a10.4,10.4,0,0,1-20.8,0V405.1A10.33,10.33,0,0,1,49.2,394.7Z" className="capsule-b fill-green" />
<path id="blue-line" d="M49.2,354.6A10.39,10.39,0,0,1,59.6,365v4.9a10.4,10.4,0,1,1-20.8,0v-5A10.31,10.31,0,0,1,49.2,354.6Z" className="capsule-c fill-blue" />
<path id="grey-line" d="M49.2,235.2a10.39,10.39,0,0,1,10.4,10.4V330a10.4,10.4,0,0,1-20.8,0V245.6a10.33,10.33,0,0,1,10.4-10.4Z" className="capsule-d fill-grey-light" />
</g>
</svg>
)
}

export default LineSvg;

Then in your index you could do something like this. Im not sure how you plan on toggling it so adjust to how you plan to toggle it.

...
const [redToggle, setRedToggle] = useState(true);
...
return (
...
<LineSvg redLineActive={redToggle}/>
<button onClick={() => setRedToggle(!redToggle}>Toggle</button>
...

There are some other ways to do it if you want multiple red line svg's but let me know.

react.js BEST WAY: show or hide html element on state change

You can always use conditions in your render method, but be sure not to use them too much. In this case, you can use

style={{ visibility: props.changeVisibilityEvent? 'visible' : 'hidden' }}> to hide the component, or use

{props.changeVisibilityEvent && <td>...}

Notice that when you use the second approach you might see 0 on your page, because the condition returns false and the render method includes the result, even if it's not a component as you wanted.



Related Topics



Leave a reply



Submit