Adding class to React Component after a certain amount of time
I don't regard it as a real change of state, as it has no affect on the application other than to give the component an animated introduction
A change of state in the component seems the natural and proper solution for this scenario. A change in a component state triggers a re-render, which is exactly what you need here. Consider that we're talking about the state of your component, not of your application here.
In React, you don't deal with the DOM directly (e.g. by using jQuery), instead your component state should "drive" what's rendered, so you let React "react" to changes in state/props and update the DOM for you to reflect the current state:
React.createComponent({
componentDidMount () {
this.timeoutId = setTimeout(function () {
this.setState({show: true});
}.bind(this), 1000);
}
componentWillUnmount () {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
}
}
render: function () {
return (<div className={this.state.show ? 'show' : null}></div>);
}
});
When using setTimeout
in React you need to be careful and make sure to cancel the timeout when the component gets unmounted, otherwise your timeout callback function will run anyway if the timeout is still pending and your component gets removed.
If you need to perform an initial mount animation or more complicated animations, consider using ReactCssTransitionGroup
, which handles timeouts and other things for you out of the box: https://facebook.github.io/react/docs/animation.html
How to make a child React component show for a certain amount of time?
I see two options:
Handle it in the parent component, only rendering
PopUpBanner
when it should be there, usingsetTimeout
to trigger a state update that re-renders the parent without renderingPopUpBanner
.Handle it in
PopUpBanner
, returningnull
fromrender
after the expiration.
I would prefer #1 over #2. But your existing code is basically doing #2, you just have to adjust render
to support it:
render() {
const message = this.props.message;
if (!message) {
return null;
}
// ...show the message...
But as discussed in teh comments, I wouldn't copy props to state like that. So instead:
constructor(props) {
super(props);
this.state = {
expiredMessage: null,
};
}
then to expire a message:
setupExpiration() {
this.expirationTimer = setTimeout(() => {
this.setState(() => ({expiredMessage: this.props.message}));
}, 1000); // <== Or however long you want it showing
}
...which you call from a couple of lifecycle methods:
componentDidMount() {
this.setupExpiration();
}
componentDidUpdate() {
this.setupExpiration();
}
and render
becomes:
render() {
const { expiredMessage } = this.state;
const { message } = this.props;
if (expiredMessage === message) {
return null;
}
// ...show the message...
But again, I'd go for having the parent in control of this, actually removing PopUpBanner
when it shouldn't be showing:
class PopUpBanner extends React.Component {
render() {
const {message} = this.props;
return <div className="banner">{message}</div>;
}
}
class Parent extends React.Component {
state = {
message: null,
};
constructor(props) {
super(props);
this.showMessage = this.showMessage.bind(this);
this.messageTimer = 0;
}
showMessage() {
clearTimeout(this.messageTimer);
this.setState({message: "Hi there, I'm a banner"});
this.messageTimer = setTimeout(() => {
this.setState({message: null});
}, 1000);
}
render() {
const {message} = this.state;
const {showMessage} = this;
return <div className="with-banner">
{message && <PopUpBanner message={message} />}
<div>
<input type="button" value="Show Message" onClick={showMessage} />
</div>
</div>;
}
};
ReactDOM.render(<Parent />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
Update React component every second
You need to use setInterval
to trigger the change, but you also need to clear the timer when the component unmounts to prevent it leaving errors and leaking memory:
componentDidMount() {
this.interval = setInterval(() => this.setState({ time: Date.now() }), 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
How to change css class after 60 seconds in react JS
Here is the proper way to update the className
in React.
First, you can store all the className
values in an array (for example ['green', 'green']
) then put the variable in a state variable (for example isColored
.
Then, update every className
using setTimeout
inside a useEffect
hook. Create one setTimeout
for one className
inside a for
loop.
To simplify the return component, you can use map
function to the state variable (isColored
).
Here is the demo https://codesandbox.io/s/jovial-curie-sm34k?file=/src/App.js.
Here is the code.
import React, { useState, useEffect } from 'react'
import './styles.css'
export default function App() {
const [ isColored, setIsColored ] = useState(['green', 'green'])
useEffect(() => {
let timer = []
for(let i = 0; i < isColored.length; i++) {
setTimeout(() => {
timer[i] = setIsColored(previousValue => {
let newValue = [...previousValue]
// update the value of className here for example 'blue'
// use '' to remove the className
newValue[i] = ''
return newValue
})
}, 60000 * (i + 1))
}
return () => {
clearTimeout(timer)
}
}, [])
return (
<div>
{isColored.map((item, index) => (
<div
key={index}
className={item}
>
</div>
))}
</div>
);
}
render a component after some time with setTimeout ( ReactJs)
If you want to do that in the Route:
import { useState } from "react";
function App() {
const [isDisplayed, setIsDisplayed] = useState(false);
useEffect(() => {
setInterval(() => {
setIsDisplayed(true);
}, 1200);
}, []);
return (
<Router>
<GlobalStyle />
<SearchProvider>
<Header />
<Switch>
<Route exact path="/">
{isDisplayed &&
<>
<InitialLoad />
<Home />
</>;
}
</Route>
//the rest of your component
React add class to one element from list after clicking on button
In order to toggle className
without using state, you can use ref
. here is an example:
const ListItem = () => {
const ref = React.createRef();
return (
<React.Fragment>
<div>
<div ref={ref} className={`text`}>
blablabla
</div>
</div>
<button
onClick={() => ref.current.classList.toggle('active')}>
Show more
</button>
</React.Fragment>
);
};
function App(){
return (
<React.Fragment>
<ListItem/>
<ListItem/>
<ListItem/>
</React.Fragment>
);
}
ReactDOM.render(<App/>, document.getElementById('root'))
.text{
color: red;
display: none;
}
.text.active{
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
React change className in x second if a specific className is active
In the handleClick
callback you can use a timeout with a random delay to toggle the "game-area-on" state.
const randomDelay = Math.random() * 3000 + 3000;
setTimeout(() => {
this.setState({
// set go state
});
}, randomDelay);
I suggest using two pieces of state, 1 to track when the app is waiting to display the "on" value, and the second to display it. Additionally, the classname can be derived from the state, so it doesn't really belong there since it's easily computed in the render method.
Here is suggested code:
class ReactionTime extends React.Component {
state = {
gameRunning: false,
isToggleOn: false,
startTime: 0,
endTime: 0
};
// timeout refs
clearOutTimer = null;
gameStartTime = null;
componentWillUnmount() {
// clear any running timeouts when the component unmounts
clearTimeout(this.clearOutTimer);
clearTimeout(this.gameStartTime);
}
handleClick = () => {
if (this.state.gameRunning) {
// handle end click
if (this.state.isToggleOn) {
clearTimeout(this.clearOutTimer);
this.setState({
gameRunning: false,
isToggleOn: false,
endTime: performance.now()
});
}
} else {
// handle start click - reaction "game" started
this.setState((prevState) => ({
gameRunning: true,
isToggleOn: false,
startTime: 0,
endTime: 0
}));
// set timeout to display "on"
const randomDelay = Math.random() * 3000 + 3000;
setTimeout(() => {
this.setState({
isToggleOn: true,
startTime: performance.now()
});
}, randomDelay);
// reaction "game" timeout to reset if user is too slow
this.clearOutTimer = setTimeout(() => {
this.setState({
gameRunning: false,
isToggleOn: false,
startTime: 0,
endTime: 0
});
}, 10000); // 10 seconds
}
};
render() {
const { gameRunning, isToggleOn, startTime, endTime } = this.state;
const className = gameRunning
? isToggleOn
? "game-area-on"
: "game-area-off"
: "game-area-start";
const reactionTime = Number(endTime - startTime).toFixed(3);
return (
<div className={className} onClick={this.handleClick}>
<h1 className="default-text">
{gameRunning
? isToggleOn
? "Go!"
: "Wait for green"
: "Click anywhere to start"}
</h1>
{reactionTime > 0 && <div>Reaction Time: {reactionTime}ms</div>}
</div>
);
}
}
When, where and how to add class to the document.body when using React.js
It's best to keep this logic outside of your component. Event emitters are a good way to abstract this.
var globalEvents = new EventEmitter();
var App = React.createClass({
setTouchMode: function(touchMode){
globalEvents.emit('touchModeChange', touchMode);
},
render: ...
});
// outside any react class
globalEvents.on('touchModeChange', function(mode){
if (mode === 2) {
$('body').addClass('touchMode');
}
else {
$('body').removeClass('touchMode');
}
});
If it really needs to be part of the state of one or more components, they can also listen to the event and update their state in the handler.
Related Topics
Unwanted CSS Injected into Posts
Why Is This Div's Calculated Height More Than Its Content
How to Prevent a Flex Item Height to Overflow Due to It's Content
How to Select Parent Pseudo-Class from Within Child Using SCSS
Configuring Compass on Windows
How to Restore The "Auto" Values for List-Style-Type in Nested Unordered Lists
Svg, Text, Font with Fixed Width/Height
CSS Infinite Animation After Hidden Is Not Reset (Chrome)
Loading Global SASS Files in Multiple Compass Projects
Ie7 and "Inherit": Ignoring Entire Rule
CSS3 /CSS - Spinning Background Image
Use Multiple Ids for Divs in CSS
How to Give Class to a Host Element in Angular 2 with @Hostbinding
How to Always Center a Flexible Square in Viewport with Pure CSS