Can't hide a DIV with React - css

I am trying to programatically hide a div when a button is clicked.
Therefore I have written the following code, but it is not working (Div is still there):
import React, {useState} from 'react';
import './Button.css';
export function Button() {
const [click, setClick] = useState(false);
const hideDiv = () => {
var display = 'block';
if (click){
display = 'none';
setClick(false);
}else{
display = 'block';
setClick(true);
}
return ([
document.getElementById('main').style.display = {display}
])
};
return(
<button className='btn' onClick={() => setClick(true), hideDiv}>Some button!</button>
);
};
I "debugged" the application with an alert and the correct display is coming, but it seems that I am missing something when applying it to the div style.
What am I missing here?

Try this approach,
export function Button() {
const [display, setDisplay] = useState("block");
const hideDiv = () => {
setDisplay(display === "none" ? "block" : "none");
};
return (
<>
{display === "block" && <div>MY DIV</div>}
<button className="btn" onClick={hideDiv}>
Some button!
</button>
</>
);
}
CODESANDBOX - https://codesandbox.io/s/wizardly-water-kf0md?file=/src/App.js

As #dai commented, you shouldn't interact directly with the DOM inside React (because it actually renders a virtual one).
Try using states instead, for example:
import React, {useState} from 'react';
import './Button.css';
export function Button() {
const [display, setDisplay] = useState(true);
const hideDiv = () => {
setDisplay(!display);
};
return (
<>
{display && (<div id='main'></div>)}
<button className='btn' onClick={hideDiv}>Some button!</button>
<>
);
};
If the div you want to add is an other component, you should use contexts instead.

Related

How to change style just one element that clicked in map React?

I want to scale only one element in the map when clicking on the picture. I read that I have to use an index but I don't know how to do it. I also saw how to do it in inline "onclick" by passing index there. But I want to do it with separated function.
Here is the code :
import './App.css';
import { useSelector, useDispatch } from 'react-redux';
import { useEffect, useState } from 'react';
import { birds, mountains,trees, search } from './features/slices/photoSlice';
function App() {
const url = useSelector((state)=>state.url)
const dispatch = useDispatch()
const [photos, setPhoto] = useState('')
const [scale, setScale] = useState(false)
const [photoindex, setPhotoindex] = useState(0)
useEffect(()=>{
fetch(url).then(res=>res.json()).then(data=>setPhoto(data))
},[url])
const handleSearch = (e) =>{
if(e.key==='Enter'){
e.preventDefault()
dispatch(search(e.target.value))
}
}
const handleClickOnPicture = (e) => {
if(e){
setScale(!scale)
}
}
return (
<div className="App">
// Problem is here below:
{photos?photos.hits.map((photo, index)=>{
return <img className={scale?'m-5 h-80 scale-125':'m-5 h-80'} onClick={handleClickOnPicture} key={photo.webformatURL} src={photo.webformatURL}/>
}):""}
</div>
</div>
</div>
);
}
export default App;
I removed half of the code, so you will see only the problem.
use event.target.classname to add/remove classes
const handleClickOnPicture = (e) => {
if(!e.target.classList.contains('scale-125')){
e.target.classList.add('scale-125')
}
else{
e.target.classList.remove('scale-125')
}
}
<img className='m-5 h-80' onClick={handleClickOnPicture} key={photo.webformatURL} src={photo.webformatURL}/>

React transition inline style won't apply

I am working with custom Transition component and my inline styling just wont apply. I tried everything what is in my power and just got myself angry. Can somebody explain why this doesn't work.
Modal show itself on initial load and by clicking on button for show or not show this doesn't react. I mean state updates correctly (this console.log shows 0 and 1 when it should) but styling just wont apply.
import classes from "./App.module.css";
import ReactDOM from "react-dom";
import React from "react";
import Modal from "./components/Modal/Modal";
import List from "./components/List/List";
import Backdrop from "./components/Backdrop/Backdrop";
import { useState } from "react";
import Transition from "react-transition-group/cjs/Transition";
function App() {
const [modalOpen, setModalOpen] = useState(false);
const onOpenModalHandler = () => {
setModalOpen(true);
};
const onCloseModalHandler = () => {
setModalOpen(false);
};
return (
<div className={classes["App"]}>
<h1>React Animations</h1>
<Transition in={modalOpen} timeout={1000} onMountEnter onMountExit>
{(state) => {
console.log(state);
console.log(state === "exiting" || state === "exited" ? 0 : 1);
return ReactDOM.createPortal(
<Modal
closeModal={onCloseModalHandler}
modalState={modalOpen}
style={{
transition: `opacity 300ms ease-out`,
opacity: state === "exiting" || state === "exited" ? 0 : 1,
}}
/>,
document.getElementById("modal")
);
}}
</Transition>
{modalOpen &&
ReactDOM.createPortal(
<Backdrop />,
document.getElementById("backdrop")
)}
<button className={"Button"} onClick={onOpenModalHandler}>
Open Modal
</button>
<h3>Animating Lists</h3>
<List />
</div>
);
}
export default App;
Modal
import classes from "./Modal.module.css";
const Modal = (props) => {
const classNames = props.modalState
? `${classes["modal-open"]} ${classes["Modal"]}`
: `${classes["modal-close"]} ${classes["Modal"]}`;
const onCloseModalHandler = () => {
props.closeModal();
};
return (
<div className={classNames}>
<h1>A Modal</h1>
<button className="Button" onClick={onCloseModalHandler}>
Dismiss
</button>
</div>
);
};
export default Modal;

An Reference Error is occured at "#polkadot/extension-dapp/bundle.js"

I tried to implement a simple UI for smart contracts using polkadot.js in the next.js framework.
The content of the WEB UI is a simple one that calls the Flipper contract, which is famous for the sample contract of the substrate.
When compiling, the following error is output. Can you tell me how to solve it?
Souce Code:
import { useEffect, useState } from "react";
import {
web3Accounts,
web3Enable,
web3FromSource,
} from "#polkadot/extension-dapp";
import { InjectedAccountWithMeta } from "#polkadot/extension-inject/types";
const Home = () => {
const [allAccount, setAllAccount] = useState<InjectedAccountWithMeta[]>([]);
const getAccounts = async () => {
const extensions = await web3Enable("my cool dapp");
if (extensions.length === 0) {
return;
}
const allAccounts = await web3Accounts();
setAllAccount(allAccounts);
};
useEffect(() => {
getAccounts();
}, []);
return (
<>
<div>
{typeof allAccount !== "undefined"
? allAccount.map((account) => {
return (
<div key={account.address}>
<div className="font-bold mb-2 text-white">
{account.address}
</div>
</div>
);
})
: ""}{" "}
</div>
</>
);
};
export default Home;
Error Information:
> Build error occurred
ReferenceError: window is not defined
at file:///Users/shin.takahashi/develop/substrate/flipper_frontend/fillper_frontend/node_modules/#polkadot/extension-dapp/bundle.js:10:13
at ModuleJob.run (node:internal/modules/esm/module_job:175:25)
at async Loader.import (node:internal/modules/esm/loader:178:24)
at async importModuleDynamicallyWrapper (node:internal/vm/module:437:15) {
type: 'ReferenceError'
}
This issue occurs because next.js is a framework for server-side rendering.
In order to avoid this problem, it is necessary to control not to execute
server-side rendering for the relevant part.
Componentize the part that gets account information from the relevant Extension.
Adopt dynamic import when using this component and set server-side rendering to off.
component sample code:
import { useEffect, useState } from "react";
import { web3Accounts, web3Enable } from "#polkadot/extension-dapp";
import { InjectedAccountWithMeta } from "#polkadot/extension-inject/types";
const Extention = () => {
const [allAccount, setAllAccount] = useState<InjectedAccountWithMeta[]>([]);
const getAccounts = async () => {
const extensions = await web3Enable("my cool dapp");
if (extensions.length === 0) {
return;
}
const allAccounts = await web3Accounts();
setAllAccount(allAccounts);
};
useEffect(() => {
getAccounts();
}, []);
return (
<>
<div>
{typeof allAccount !== "undefined"
? allAccount.map((account) => {
return (
<div key={account.address}>
<div className="font-bold mb-2 text-white">
{account.address}
</div>
</div>
);
})
: ""}{" "}
</div>
</>
);
};
export default Extention;
Calling component sample code:
import dynamic from "next/dynamic";
import { useState } from "react";
const Extention = dynamic(() => import("../component/extention"), {
ssr: false,
});
const Home = () => {
const [showExtention, setShowExtention] = useState(false);
return (
<>
<button onClick={() => setShowExtention(true)}>show extention</button>
{showExtention == true && <Extention></Extention>}
</>
);
};
export default Home;

Typescript: Clicking 'X' doesn't successfully close my popup banner

I've created a popup banner with the following code (sorry if the format is off)
//this is in folder Banner.tsx
import React, {useCallback} from "react";
type Properties = {
close: () => void;
text: string;
const Banner: React.FC<Properties> = ({close, text}) => {
const onClick = useCallback(() => {
close();},
[close, text]);
return (
<div className = "BannerBox">
<div className = "banner">
<span className = "popup"> {onClick}{close}[x]
</span>
{text}
</div>
</div>
);
};
export default Banner;
//this is App.tsx
import Banner from "./Components/Banner";
function App(): JSX.Element {
const [isOpen, setIsOpen]=useState(false);
const toggleBanner = () => {
SetIsOpen(!isOpen);
};
return (
<div>
<input type = "button"
value = "popup"
onClick={toggleBanner}/>
<p>hi</p>
{isOpen && <Banner text = {"hello"} close={function (): void { throw new Error("Function not implemented.");
} }/>}
</div>
export default App;
//this is my Banner.css file (let me know if you need the full code but this is some of it)
.BannerBox{
position: fixed;
background: blue;
width:50%;
}
.banner{
position: relative;
width: 100%;
}
.popup{
content: 'x';
position: fixed;
background: green;
}
the code compiles just fine, I'm not getting any errors but the problem is that when the banner pop-ups, I can't close it by clicking 'X' i have to refresh the page in order to close the banner and I'm not sure how to fix that. Any help is appreciated!
The close function needs to be passed to the onClick callback for the span which is acting as the button. These are added as "attributes" for the jsx element. See below onClick={onClick} where your onClick callback function is passed by reference (notice no invoking parentheses within the curly braces)
In the return of Banner.tsx
<span className="popup" onClick={onClick}>
[x]
</span>
close is passed into your Banner component, so this needs to be implemented in your App component. I ensured it always closes by explicitly setting isOpen to false (instead of calling toggle)
in the return of App.tsx
{isOpen && <Banner text={"hello"} close={() => setIsOpen(false)} />}
so in total
Banner.tsx
import React, { useCallback } from "react";
import "./Banner.css";
type Properties = {
close: () => void;
text: string;
};
const Banner: React.FC<Properties> = ({ close, text }) => {
const onClick = useCallback(() => {
close();
}, [close]);
return (
<div className="BannerBox">
<div className="banner">
<span className="popup" onClick={onClick}>
[x]
</span>
{text}
</div>
</div>
);
};
export default Banner;
and App.tsx
import React, { useState } from "react";
import Banner from "./Components/Banner";
function App(): JSX.Element {
const [isOpen, setIsOpen] = useState(false);
const toggleBanner = () => {
setIsOpen(!isOpen);
};
return (
<div>
<input type="button" value="popup" onClick={toggleBanner} />
<p>hi</p>
{isOpen && <Banner text={"hello"} close={() => setIsOpen(false)} />}
</div>
);
}
export default App;
See codesandbox here
Let's assume that close() will actually close the popup banner since you did't show the implementation of it.
This line causes the issue
<span className = "popup">{onClick}{close}[x]</span>
You are supposed to pass a function to the onClick listener. Something like:
<span className = "popup" onClick={close}>[x]</span>

Change style of functional component after click

The AnswerScreen component is loading a set of MyButton components. I want to change the style (basically the backgroundColor of the MyButton that was click. The code doesn't work as intended. I see that on a class component I would be able to do it with this.className but in a functional component I cannot use this (although I have the key). Any tips?
import React from 'react';
import classes from './AnswerScreen.module.css';
import MyButton from '../../../../utils/MyButton';
const AnswerScreen = (props) => {
const buttonClickHandler = (index, value) => {
if (props.myValue !== value) {
classes.AnswerScreenButton = {
fontSize: '3rem',
cursor: 'pointer',
backgroundColor: 'red'
}
}
}
return (
<div className={classes.AnswerScreen}>
{props.buttons.map((value, index) => {
return <MyButton
className={classes.AnswerScreenButton}
clickHandler={() => buttonClickHandler(index, value)}
key={index}
num = {value} />
})}
</div>
);
}
export default AnswerScreen;
I assume you want to keep track of which button was pressed in the end? I suggest you add a state variable to keep track of the selected button. You can use that state variable to set the correct classname of the button. Add the class AnswerScreenButtonSelected that contains css for a selected button. I removed your usage of index, they should be avoided when setting keys in mapped arrays in React.
import React from 'react';
import classes from './AnswerScreen.module.css';
import MyButton from '../../../../utils/MyButton';
const AnswerScreen = (props) => {
const [selectedButton, setSelectedButton] = useState(null);
return (
<div className={classes.AnswerScreen}>
{props.buttons.map( value =>
<MyButton
key={value}
className={selectedButton === value ? classes.AnswerScreenButtonSelected : classes.AnswerScreenButton}
clickHandler={() => setSelectedButton(value)}
num = {value} />
)}
</div>
);
}
export default AnswerScreen;

Resources