I wrote CSS. This works fine for blur.
document.addEventListener("click", () => {
document.querySelector(".transition").classList.toggle("blur");
})
.transition {
transition: 5s;
filter: blur(0px);
}
.blur {
filter: blur(5px);
}
<div class="transition">
TEXT
</div>
However, this will not work with React.js and Styled Components. I want to realize transition by filter without using add-on. Why doesn't this work, and how does it work?
CodeSandBox Demo
const Button = styled.button``;
let ToggleBlurText = styled.div`
transition: "5s"
`;
function App() {
const [blur, setBlur] = useState(false);
useEffect(() => {
ToggleBlurText = styled.div`
filter: blur(${blur ? "0px" : "5px"});
transition: "5s"
`;
}, [blur]);
return (
<div className="App">
<ToggleBlurText>
<h2>TEXT</h2>
</ToggleBlurText>
<Button onClick={() => setBlur(!blur)}>button</Button>
</div>
);
}
That approach will not work. React probably won't re-render the ToggleBlurText component and the styles inside the effect will not be applied.
Instead, you can create a styled component and toggle a css class that changes the blur depending on your state.
const Button = styled.button``;
const ToggleBlurText = styled.div`
transition: 5s;
filter: blur(0px);
&.blur {
filter: blur(5px);
}
`;
function App() {
const [blur, setBlur] = useState(false);
return (
<div className="App">
<ToggleBlurText className={blur ? 'blur' : ''}>
<h2>TEXT</h2>
</ToggleBlurText>
<Button onClick={() => setBlur(prev => !prev)}>button</Button>
</div>
);
}
I also fixed a typo in your styled component css and also changed the onClick handler slightly.
Related
In react-js I have two div and two button, 1st button click fist div show and second button click second div show and 1st div hide
export default function Provider() {
let firstClick = () => {
const itemList = document.querySelector(".firstdiv");
const itemList2 = document.querySelector(".Seconddiv");
itemList.style.display = "block";
itemList2.style.display = "none";
}
let secondClick = () => {
const itemList = document.querySelector(".firstdiv");
const itemList2 = document.querySelector(".Seconddiv");
itemList.style.display = "none";
itemList2.style.display = "block";
}
return (
<div className="firstdiv">First Div Content</div>
<div className="Seconddiv">Second Div Content</div>
<button onClick={firstClick}>First Button</button>
<button onClick={secondClick}>Second Button</button>
})
I use this method is use in react how to rewrite the code in react way, I am new in react and thanks in advance
Using React you would go about this a bit different:
instead of hiding components by css, you would render or not render components.
A compact example:
const SomeDiv = () => {
const [showFirst, setShowFirst] = useState(true);
// sets showFirst to not the value of showFirst and triggers a render
const toggle = () => setShowFirst(!showFirst);
return showFirst
? <button onClick={toggle}>First</button>
: <button onClick={toggle}>Second</button>
}
You can do something like that:
import { useState } from "react";
export default function HealthcareProvider() {
const [hide, setHide] = useState(false);
const toggleHide = () => {
setHide(!hide);
};
return (
<div>
<div className="firstdiv"
style={{ display: hide ? "block" : "none" }}>
First Div Content
</div>
<div className="Seconddiv" style={{ display: hide ? "none" : "block" }}>
Second Div Content
</div>
<button onClick={toggleHide}>First Button</button>
<button onClick={toggleHide}>Second Button</button>
</div>
);
}
I am trying to make a Modal component. I would like that when the modal appears, it appears with a transition just like when it disappears. This is currently very jerky, why and how can I fix it?
I would like that when the modal is shown it is shown with an animation and the same behavior when the modal disappears (click on the button).
thank you very much for the help, I know I will learn a lot.
//content of styles.css
.modal {
position: absolute;
width: 100%;
height: 100%;
background: red;
transition: all 300ms ease-out;
transform: translateY(100%);
}
.show {
transform: translateY(0%);
}
.hide {
transform: translateY(100%);
}
app.js
import Modal from "./modal";
/*
const Modal = ({ show, children }) => {
return <div className={`modal ${show ? "show" : "hide"}`}>.
{children} </div>;
};
export default Modal;
*/
import ModalContent from "./modalContent";
/*
const ModalContent = ({ show }) => {
const showModal = () => {
show();
};
return <button onClick={showModal}> close modal</button>;
};
export default ModalContent;
*/
export default function App() {
const [show, setShow] = useState(false);
const closeModal = () => {
setShow(false);
};
useEffect(() => setShow(true), []);
return (
<div className="App">
{show && (
<Modal show={show}>
<ModalContent show={closeModal} />
</Modal>
)}
</div>
);
}
I updated my code:
this is my live code
First of all, in your demo modal disappears immediately, without any transition. It seems, that it's cause by re-rendering of whole App component, on show state change. Extracting Modal component out of App do the trick for me:
const Modal = ({ show, children }) => {
useEffect(() => {}, [show]);
return <div className={`modal ${show ? "show" : "hide"}`}>{children} </div>;
};
export default function App() {
Second point - you can't control initial setup just with with css transition. Transition appears when something (class, attribute, pseudoclass) changes on the given element. To get around this and have smooth modal appearance, you can setup one-time useEffect in the App component, which will change show state from false to true. My overall snippet:
const Modal = ({ show, children }) => {
return <div className={`modal ${show ? "show" : "hide"}`}>{children} </div>;
};
export default function App() {
const ModalContent = ({ show }) => {
const showModal = () => {
show();
};
return <button onClick={showModal}> close modal</button>;
};
const [show, setShow] = useState(false);
const closeModal = () => {
setShow(false);
};
useEffect(() => setShow(true), [])
return (
<div className="App">
<Modal show={show}>
<ModalContent show={closeModal} />
</Modal>
</div>
);
}
I have been searching for a while but can't seem to find a concrete answer to this problem. I have encountered this many times and overcame them by using "hacky" solutions. What is the recommended/standard way to get around child components re-rendering when setting parent state.
I have made a very simple example to show this problem where we have a left side child component with a count state and a right side child component which displays text when a button on the left side is clicked.
Example.js
import React, { useState } from "react";
import "../css/pages/Example.css";
function Example() {
const [rightText, setRightText] = useState();
const LeftSide = () => {
const [count, setCount] = useState(0);
return (
<div className="egleft">
<p>{count}</p>
<button
onClick={() => {
setCount(count + 1);
}}
>
Add
</button>
<button
onClick={() => {
setRightText("hello world");
}}
>
Update right
</button>
</div>
);
};
const RightSide = () => {
return <div className="egright">{rightText && <p>{rightText}</p>}</div>;
};
return (
<div className="wrapper">
<LeftSide />
<RightSide />
</div>
);
}
export default Example;
Example.css
.wrapper {
width: 300px;
height: 300px;
border: 1px solid red;
display: flex;
}
.egleft {
border: 1px solid green;
width: 50%;
}
.egleft p,
.egright p {
color: black;
}
.egright {
width: 50%;
border: 1px solid blue;
}
To replicate: click add button to increment value on left side.. then click update right. You will see due to the parent's setState, left side is re-rendered, causing its own count state to be reset to the initial value.
Here is a gif showing the problem
Thanks
The issue is you are creating the LeftSide (and it's state) and RightSide components on the fly each time the Example component re-renders.
It's not common practice to create child components inside the render function of the parent as it creates an unecessary overhead (creating a new function every render instead of using the same existing function). You can split up the components into multiple functions in the root of the file, or multiple files, and compose them like #dejan-sandic answer.
But if creating the child component inside the render function is a must. You can use the useMemo hook to stop react from recreating your child component:
import React, { useState, useMemo } from "react";
import "../css/pages/Example.css";
function Example() {
const [rightText, setRightText] = useState();
const LeftSide = useMemo(() => () => {
const [count, setCount] = useState(0);
return (
<div className="egleft">
<p>{count}</p>
<button
onClick={() => {
setCount(count + 1);
}}
>
Add
</button>
<button
onClick={() => {
setRightText("hello world");
}}
>
Update right
</button>
</div>
);
}, []);
const RightSide = () => {
return <div className="egright">{rightText && <p>{rightText}</p>}</div>;
};
return (
<div className="wrapper">
<LeftSide />
<RightSide />
</div>
);
}
export default Example;
But I would advise against it, as it can become unnecessarily complex, unless for something extremely dynamic.
You are defining both RightSide and the LeftSide components inside of Example. You can't do that because those two components will be created every time` Example component renders, which is happening after every statechange.
const RightSide = () => {
return <div className="egright">{rightText && <p>{rightText}</p>}</div>;
};
Do this in stead:
const LeftSide = ({ setRightText }) => {
const [count, setCount] = useState(0);
return (
<div className="egleft">
<p>{count}</p>
<button
onClick={() => {
setCount(count + 1);
}}
>
Add
</button>
<button
onClick={() => {
setRightText("hello world");
}}
>
Update right
</button>
</div>
);
};
const RightSide = ({ rightText }) => {
return <div className="egright">{rightText && <p>{rightText}</p>}</div>;
};
function Example() {
const [rightText, setRightText] = useState();
return (
<div className="wrapper">
<LeftSide rightText={rightText} />
<RightSide setRightText={setRightText} />
</div>
);
}
I have a component which renders a react-modal, my problem is the react-modal does not open. modalFileNameOpen useState property does not set properly.
const [modalFileNameOpen, setmodalFileNameOpen] = useState(false)
const handleFileNameChangeClick = () => {
console.log(modalFileNameOpen) // set to false
setmodalFileNameOpen(true) // this does not set the `modalFileNameOpen` to true.
console.log(modalFileNameOpen) // is still false
}
return (
<div className="container-fluid">
<input type="button" className="btn" onClick={handleFileNameChangeClick} value="Rename File"></input>
<ModalFileName modalFileNameOpen={modalFileNameOpen} />
</div>
)
I have another component ModalFileName
import React, { useState } from 'react';
import Modal from 'react-modal';
Modal.setAppElement('#root');
const ModalFileName = ({ modalFileNameOpen }) => {
const [modalIsOpen, setModalIsOpen] = useState(modalFileNameOpen)
return (
<Modal isOpen={modalIsOpen} onRequestClose={() => setModalIsOpen(false)}>
<div>
<h1>File Name Change</h1>
<div>
<button onClick={() => setModalIsOpen(false)}>Close</button>
</div>
</div>
</Modal>
)
}
export default ModalFileName;
Here is a minimal example of what you seem to be trying to achieve.
It is a basic illustration of pulling state up to the parent and passing a handler function down to the child. In your code you were attempting to do this by declaring a new state in the child based on the parent's state which leads to unnecessary duplication and possible state conflicts down the road.
We declare our modal state and setter and a basic handler function:
const [openModal, setOpenModal] = useState(false);
const toggleModal = () => {
setOpenModal(!openModal);
}
We then conditionally render our modal component based on the current state value. If openModal is false we render the button to open it, otherwise we render the Modal component and pass our handler function toggleModal to it as a prop.
// if openModal is false render the button, else render our modal
{!openModal ?
<button type="button" onClick={toggleModal}>Open Modal</button>
: <Modal handler={toggleModal} />
}
If the modal is rendered it recieves the handler (here retrieved through destructuring function Modal({handler}) {...) and assign it to the onClick of the close button on our modal.
function Modal({handler}) {
return (
<div className="modal" >
<p>I'm a modal</p>
<button type="button" onClick={handler}>Close Modal</button>
</div>
)
}
Working Example
body {
padding: 0;
margin: 0;
}
.container {
position: relative;
height: 100vh;
width: 100vw;
background: gray;
}
.modal {
height: 50vh;
width: 50vw;
position: absolute;
top: 25%;
left: 50%;
transform: translateX(-50%);
background-color: aqua;
}
<script src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<div id="App"></div>
<script type="text/babel">
const {useState} = React;
function App() {
const [openModal, setOpenModal] = useState(false);
const toggleModal = () => {
setOpenModal(!openModal);
}
return (
<div className="container">
{!openModal ?
<button type="button" onClick={toggleModal}>Open Modal</button>
: <Modal handler={toggleModal} />
}
</div>
)
}
function Modal({handler}) {
return (
<div className="modal" >
<p>I'm a modal</p>
<button type="button" onClick={handler}>Close Modal</button>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('App'));
</script>
Some notes
If you console.log() before and after the setOpenModal() call you will get the same results that you did in your question; it will print the same value that it entered the render with. If it doesn't there is a problem and you have mutated the state. From the Docs
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
const [openModal, setOpenModal] = useState(false);
const toggleModal = () => {
console.log(openModal); // prints the value of openModal on entering render
setOpenModal(!openModal); // sets openModal to !openModal
console.log(openModal); // prints the value of openModal on entering render
}
Also, you may want to pass arguments to your passed handler (arguably the close button should always set openModal to false rather than hoping that toggling it will close it).
To do this you can simply accept an argument in your handler function.
const toggleModal = (newState) => {
setOpenModal(newState);
}
and pass it in your onClick calls.
<button type="button" onClick={() => toggleModal(true)}>Open Modal</button>
function Modal({handler}) {
return (
<div className="modal" >
<p>I'm a modal</p>
<button type="button" onClick={() => handler(false)}>Close Modal</button>
</div>
)
}
i want to display a dialog to the bottom right corner of the page on clickin a button using react and typescript.
There is a button named "Add" in ListComponent. when clicking that button dialog which is the DialogComponent should be rendered.
Below is how the ListComponent and DialogComponent looks
function ListComponent() {
const onAddClicked = () => {
//what to be done
}
return (
<button onClick={onAddClicked}> Add</button>
);
}
function DialogComponent() {
return (
<Wrapper> Dialog </Wrapper>
)
}
Now i cannot call DailogComponent within ListComponent as it would push the layout of the page.
So i want to call this DailogComponent within MainComponent which is something like below
function Main () {
return (
<ListComponent>
//some props
</ListComponent>
)
}
I am new to using react with typescript. How can i do this. could someone provide some insights into this. thanks.
You will likely want to use fixed positioning (and possibly some increased z-index, if necessary) to display a dialog box at the bottom right of the screen. This will "break" it out of being rendered "inline" with your content.
At a minimum you should utilize the following CSS rules
position: fixed;
bottom: <M>; // M units from the bottom
right: <N>; // N units from the right
The linked codesandbox sets this Dialog class style and component
CSS
.dialog {
position: fixed;
bottom: 1rem;
right: 1rem;
padding: 1rem;
border-radius: 5px;
background-color: lightblue;
}
JSX
const Dialog = ({ showDialog, text }) =>
showDialog ? <div className="dialog">{text}</div> : null;
How you toggle the display state of the dialog is up to you.
EDIT: Full code with a demo ListComponent
const Dialog = ({ showDialog, text }) =>
showDialog ? <div className="dialog">{text}</div> : null;
const ListComponent = ({ data, toggleDialog }) =>
data.map((el, i) => (
<div key={i}>
<button type="button" onClick={toggleDialog}>
{el}
</button>
</div>
));
export default function App() {
const [showDialog, setShowDialog] = useState();
const toggleDialog = () => setShowDialog(s => !s);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button type="button" onClick={toggleDialog}>
Toggle Dialog in Main
</button>
<h2>List Component</h2>
<ListComponent data={["A", "B", "C"]} toggleDialog={toggleDialog} />
<Dialog showDialog={showDialog} text="I'm a dialog" />
</div>
);
}
This is essentially applying Lifted State. State and mutators are lifted to a common ancestor of components interested in either displaying the state, or updating. State and state updaters are passed as props to children.
You need to have a callback in order to display the dialog box from Main function.
Below is an example:
import React, { useState } from "react";
import { render } from "react-dom";
import Modal from "react-modal";
const Main = () => {
const [isOpen, setIsOpen] = useState(false);
const handleAddClick = () => {
setIsOpen(true);
};
return (
<React.Fragment>
<ListComponent onAddClickedProps={handleAddClick} />
<DialogComponent isOpen={isOpen} />
</React.Fragment>
);
};
const ListComponent = ({ onAddClickedProps }) => {
const onAddClicked = () => {
onAddClickedProps();
};
return <button onClick={onAddClicked}> Add</button>;
};
const DialogComponent = ({ isOpen }) => {
return (
<Modal isOpen={isOpen}>
<div>I am a modal</div>
</Modal>
);
};
render(<Main />, document.getElementById("root"));
React-modal-example-on-sandbox