Adding Class to React Component After a Certain Amount of Time

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:

  1. Handle it in the parent component, only rendering PopUpBanner when it should be there, using setTimeout to trigger a state update that re-renders the parent without rendering PopUpBanner.

  2. Handle it in PopUpBanner, returning null from render 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>
);
}
}

Edit react-change-classname-in-x-second-if-a-specific-classname-is-active

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



Leave a reply



Submit