I am trying to delay animation at the beginning in gsap, it plays immediately it downloads, this is my first time using gsap. I tried adding pause but it didn't do anything, not sure if I am using it wrongly .Below is the code for what I tried out, the animation works but i have tried pause and it doesnt.
class About extends Component {
constructor(props) {
super(props);
this.header = React.createRef();
}
componentDidMount() {
const tl = gsap.timeline({
paused: true
});
gsap.from(this.header.current, 0.7, {
translateY: 80,
ease: "power2.out",
autoAlpha: 0,
});
}
render() {
return (
<div className="caption">
<h3 className="header" ref={this.header}>
Get to Know <span>Us</span>
<Circle className="circle" />
</h3>
<p className="body" ref={this.words}>
We offer you the flexibility to receive and send money using
cash transfers.
</p>
)
}
}
It isn't that clear what you are trying to do, but I guess maybe you can simply use async function combined with a promise.
For pseudo)
foo = (delay) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, delay)
})
}
bar = async() => {
await foo();
// something you want to do with gsap
}
componentDidMount(){
this.bar();
}
All I had to do was just add "delay:1"
Related
I'm trying to do what I thought would be a simple task. On submit of the form that is pulled in by the GravityForm component, I set the handleSubmit state to true which then renders the thank you message (this all works fine, I've removed the URLs but I can assure you this bit is fine).
My issue comes when I load the success message. The setTimeout function displays the id. Is there a way I can either stop it displaying that id or implement this function in a different way that means it won't show?
The expected functionality is that the thank you message will display for 3 seconds and then the page will load to a different site.
import "./form.css";
import React, { Component } from "react";
import GravityForm from "react-gravity-form";
import styled from "styled-components";
export class Gravity extends Component {
state = {
handleSubmit : false,
}
successMessage = styled.div`
display: block;
color: #fff;
font-size: 24px;
text-align: center;
`;
render() {
const { handleSubmit } = this.state;
if (!handleSubmit) {
return (
<GravityForm
backendUrl="https://removedurlforclientprivacy.com/wp-json/glamrock/v1/gf/forms"
formID="3"
onSubmitSuccess={ () => {
this.setState({
handleSubmit : true,
})
} }
/>
);
} else {
return (
<>
<this.successMessage>
<p>Thanks for entering our competition!<br />If you're our lucky winner, we will let you know.</p>
</this.successMessage>
{ setTimeout(() => window.location.href = 'https://google.co.uk', 3000) }
</>
)
}
}
}
export default Gravity
The reason you're seeing the id is because the setTimeout function returns the id. Imagine the setTimeout() call simply being replaced with 123, so that it would look like { 123 }, it will of course show the 123 value.
A way you can suppress the value is by converting it into an expression to be evaluated - something like { 123 && <></> }, that way the empty element will be returned instead of the value itself (obviously replacing the 123 with your setTimeout() function as follows:
{ setTimeout(() => window.location.href = 'https://google.co.uk', 3000) && <></> }
You could also play around with { 123 && undefined } or { 123 && null }, which would likely result in not even returning an element at all, again ensuring to replace 123 with your setTimeout() function.
Can you please try this way, Create a function which you can set your success things and call it on your else condition
renderSuccesssMessage = () => {
setTimeout(() => window.location.href = 'https://google.co.uk', 3000)
return (
<this.successMessage>
<p>Thanks for entering our competition!<br />If you're our lucky winner, we will let you know.</p>
</this.successMessage>
)
}
And Just call this function into your else condtion
else {
return (
this.renderSuccessMessage()
)
}
You can change your onSubmitSuccess function like below one and remove setTimeout from else block :
onSubmitSuccess={() => {
this.setState({
handleSubmit : true,
},() => {
setTimeout(() => window.location.href = 'https://google.co.uk', 3000)
});
}}
You can write it to the console or use an empty auxiliary function.
function do_nothing () {}
{ console.info(setTimeout(() => window.location.href = 'https://google.co.uk', 3000)) }
{ do_nothing(setTimeout(() => window.location.href = 'https://google.co.uk', 3000)) }
Hello guys ? So i'm developing web with React right now, and i need to make stopwatch timer that will be played when i click the button, so i use setInterval() method. But when i click the button and setInterval() is running, i got this warning from why-did-you-update library, which means to avoid re-rendering. I already use PureComponent but why when setInterval() is running some component still re-render? it makes lag guys, and if i stop setInterval with clearInterval() method the component is stop re-rendering.
The code just like this:
startTimer() {
// Test
this.setState(
prevState => ({
...prevState,
isSessionStarted: true,
duration: prevState.duration,
startedAt: Date.now() - prevState.duration
}),
() => {
this.timer = setInterval(
() =>
this.setState(prevState => ({
duration: Date.now() - prevState.startedAt
})),
1000
);
}
);
}
stopTimer() {
this.setState({ isSessionFinished: true }, () => {
clearInterval(this.timer);
});
}
Any solution? Thank you before.
My camera is acting weird. When I take a picture, it will turn off right away. But when my component unmounts, it can take up to 10 seconds before my camera turns off, even though the exact same function is being called. I assume it's still turned on since the "camera light" is still turned on. Here's the logic behind:
class Webcam extends React.Component<Props> {
...
videoRef: any = React.createRef();
componentWillUnmount() {
this.destroyCam();
}
destroyCam() {
this.videoRef.srcObject.getTracks().forEach((track: MediaStream) => {
track.stop();
});
}
onShoot = () => {
var timer = setInterval(() => {
this.countdown--;
if (this.countdown === 0) {
this.destroyCam();
clearInterval(timer);
}
}, 1000);
};
render() {
return(
...
<video ref={el => (this.videoRef = el)}/>
)
}
}
Like I said, when the onShoot is fired, it turns off the camera immediately. Why doesn't it when unmounting the component?
I've been trying to make a stopwatch in react and redux. I've been having trouble trouble figuring out how to design such a thing in redux.
The first thing that came to mind was having a START_TIMER action which would set the initial offset value. Right after that, I use setInterval to fire off a TICK action over and over again that calculates how much time has passed by using the offset, adds it to the current time, and then updates the offset.
This approach seems to work, but I'm not sure how I would clear the interval to stop it. Also, it seems like this design is poor and there is probably a better way to do it.
Here is a full JSFiddle that has the START_TIMER functionality working. If you just want to see what my reducer looks like right now, here it is:
const initialState = {
isOn: false,
time: 0
};
const timer = (state = initialState, action) => {
switch (action.type) {
case 'START_TIMER':
return {
...state,
isOn: true,
offset: action.offset
};
case 'STOP_TIMER':
return {
...state,
isOn: false
};
case 'TICK':
return {
...state,
time: state.time + (action.time - state.offset),
offset: action.time
};
default:
return state;
}
}
I would really appreciate any help.
I would probably recommend going about this differently: store only the state necessary to calculate the elapsed time in the store, and let components set their own interval for however often they wish to update the display.
This keeps action dispatches to a minimum — only actions to start and stop (and reset) the timer are dispatched. Remember, you're returning a new state object every time you dispatch an action, and each connected component then re-renders (even though they use optimizations to avoid too many re-renders inside the wrapped components). Furthermore, many many action dispatches can make it difficult to debug app state changes, since you have to deal with all the TICKs alongside the other actions.
Here's an example:
// Action Creators
function startTimer(baseTime = 0) {
return {
type: "START_TIMER",
baseTime: baseTime,
now: new Date().getTime()
};
}
function stopTimer() {
return {
type: "STOP_TIMER",
now: new Date().getTime()
};
}
function resetTimer() {
return {
type: "RESET_TIMER",
now: new Date().getTime()
}
}
// Reducer / Store
const initialState = {
startedAt: undefined,
stoppedAt: undefined,
baseTime: undefined
};
function reducer(state = initialState, action) {
switch (action.type) {
case "RESET_TIMER":
return {
...state,
baseTime: 0,
startedAt: state.startedAt ? action.now : undefined,
stoppedAt: state.stoppedAt ? action.now : undefined
};
case "START_TIMER":
return {
...state,
baseTime: action.baseTime,
startedAt: action.now,
stoppedAt: undefined
};
case "STOP_TIMER":
return {
...state,
stoppedAt: action.now
}
default:
return state;
}
}
const store = createStore(reducer);
Notice the action creators and reducer deals only with primitive values, and does not use any sort of interval or a TICK action type. Now a component can easily subscribe to this data and update as often as it wants:
// Helper function that takes store state
// and returns the current elapsed time
function getElapsedTime(baseTime, startedAt, stoppedAt = new Date().getTime()) {
if (!startedAt) {
return 0;
} else {
return stoppedAt - startedAt + baseTime;
}
}
class Timer extends React.Component {
componentDidMount() {
this.interval = setInterval(this.forceUpdate.bind(this), this.props.updateInterval || 33);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
const { baseTime, startedAt, stoppedAt } = this.props;
const elapsed = getElapsedTime(baseTime, startedAt, stoppedAt);
return (
<div>
<div>Time: {elapsed}</div>
<div>
<button onClick={() => this.props.startTimer(elapsed)}>Start</button>
<button onClick={() => this.props.stopTimer()}>Stop</button>
<button onClick={() => this.props.resetTimer()}>Reset</button>
</div>
</div>
);
}
}
function mapStateToProps(state) {
const { baseTime, startedAt, stoppedAt } = state;
return { baseTime, startedAt, stoppedAt };
}
Timer = ReactRedux.connect(mapStateToProps, { startTimer, stopTimer, resetTimer })(Timer);
You could even display multiple timers on the same data with a different update frequency:
class Application extends React.Component {
render() {
return (
<div>
<Timer updateInterval={33} />
<Timer updateInterval={1000} />
</div>
);
}
}
You can see a working JSBin with this implementation here: https://jsbin.com/dupeji/12/edit?js,output
If you are going to use this in a bigger app then I would use requestAnimationFrame instead of an setInterval for performance issues. As you are showing milliseconds you would notice this on mobile devices not so much on desktop browsers.
Updated JSFiddle
https://jsfiddle.net/andykenward/9y1jjsuz
You want to use the clearInterval function which takes the result of a call to setInterval (a unique identifier) and stops that interval from executing any further.
So rather than declare a setInterval within start(), instead pass it to the reducer so that it can store its ID on the state:
Pass interval to dispatcher as a member of the action object
start() {
const interval = setInterval(() => {
store.dispatch({
type: 'TICK',
time: Date.now()
});
});
store.dispatch({
type: 'START_TIMER',
offset: Date.now(),
interval
});
}
Store interval on new state within the START_TIMER action reducer
case 'START_TIMER':
return {
...state,
isOn: true,
offset: action.offset,
interval: action.interval
};
______
Rendering the component according to interval
Pass in interval as a property of the component:
const render = () => {
ReactDOM.render(
<Timer
time={store.getState().time}
isOn={store.getState().isOn}
interval={store.getState().interval}
/>,
document.getElementById('app')
);
}
We can then inspect the state within out component to render it according to whether there is a property interval or not:
render() {
return (
<div>
<h1>Time: {this.format(this.props.time)}</h1>
<button onClick={this.props.interval ? this.stop : this.start}>
{ this.props.interval ? 'Stop' : 'Start' }
</button>
</div>
);
}
______
Stopping the timer
To stop the timer we clear the interval using clearInterval and simply apply the initialState again:
case 'STOP_TIMER':
clearInterval(state.interval);
return {
...initialState
};
______
Updated JSFiddle
https://jsfiddle.net/8z16xwd2/2/
Similar to andykenward's answer, I would use requestAnimationFrame to improve performance as the frame rate of most devices is only about 60 frames per second. However, I would put as little in Redux as possible. If you just need the interval to dispatch events, you can do that all at the component level instead of in Redux. See Dan Abramov's comment in this answer.
Below is an example of a countdown Timer component that both shows a countdown clock and does something when it has expired. Inside the start, tick, or stop you can dispatch the events that you need to fire in Redux. I only mount this component when the timer should start.
class Timer extends Component {
constructor(props) {
super(props)
// here, getTimeRemaining is a helper function that returns an
// object with { total, seconds, minutes, hours, days }
this.state = { timeLeft: getTimeRemaining(props.expiresAt) }
}
// Wait until the component has mounted to start the animation frame
componentDidMount() {
this.start()
}
// Clean up by cancelling any animation frame previously scheduled
componentWillUnmount() {
this.stop()
}
start = () => {
this.frameId = requestAnimationFrame(this.tick)
}
tick = () => {
const timeLeft = getTimeRemaining(this.props.expiresAt)
if (timeLeft.total <= 0) {
this.stop()
// dispatch any other actions to do on expiration
} else {
// dispatch anything that might need to be done on every tick
this.setState(
{ timeLeft },
() => this.frameId = requestAnimationFrame(this.tick)
)
}
}
stop = () => {
cancelAnimationFrame(this.frameId)
}
render() {...}
}
I'm trying to load a splash screen for an iOS app built in React Native. I'm trying to accomplish this through class states and then a setTimeout function as follows:
class CowtanApp extends Component {
constructor(props){
super(props);
this.state = {
timePassed: false
};
}
render() {
setTimeout(function(){this.setState({timePassed: true})}, 1000);
if (!this.state.timePassed){
return <LoadingPage/>;
}else{
return (
<NavigatorIOS
style = {styles.container}
initialRoute = {{
component: LoginPage,
title: 'Sign In',
}}/>
);
}
}
}
The loading page works for a second, and then I guess when setTimeout tries to change the state to true, my program crashes: 'undefined is not an object (evaluating this.setState)'. I've been going at this for a couple of hours, any ideas on how to fix it?
Classic javascript mistake.
setTimeout(function(){this.setState({timePassed: true})}, 1000)
When setTimeout runs this.setState, this is no longer CowtanApp, but window. If you define the function with the => notation, es6 will auto-bind this.
setTimeout(() => {this.setState({timePassed: true})}, 1000)
Alternatively, you could use a let that = this; at the top of your render, then switch your references to use the local variable.
render() {
let that = this;
setTimeout(function(){that.setState({timePassed: true})}, 1000);
If not working, use bind.
setTimeout(
function() {
this.setState({timePassed: true});
}
.bind(this),
1000
);
Write a new function for settimeout. Pls try this.
class CowtanApp extends Component {
constructor(props){
super(props);
this.state = {
timePassed: false
};
}
componentDidMount() {
this.setTimeout( () => {
this.setTimePassed();
},1000);
}
setTimePassed() {
this.setState({timePassed: true});
}
render() {
if (!this.state.timePassed){
return <LoadingPage/>;
}else{
return (
<NavigatorIOS
style = {styles.container}
initialRoute = {{
component: LoginPage,
title: 'Sign In',
}}/>
);
}
}
}
const getData = () => {
// some functionality
}
const that = this;
setTimeout(() => {
// write your functions
that.getData()
},6000);
Simple, Settimout function get triggered after 6000 milliseonds
In case anyone wants it, you can also make the timer async and await it:
export const delay = (ms) => new Promise((res) => setTimeout(res, ms));
Usage:
// do something
await delay(500); // wait 0.5 seconds
// do something else
Change this code:
setTimeout(function(){this.setState({timePassed: true})}, 1000);
to the following:
setTimeout(()=>{this.setState({timePassed: true})}, 1000);
On ReactNative .53, the following works for me:
this.timeoutCheck = setTimeout(() => {
this.setTimePassed();
}, 400);
'setTimeout' is the ReactNative library function.
'this.timeoutCheck' is my variable to hold the time out object.
'this.setTimePassed' is my function to invoke at the time out.
You can bind this to your function by adding .bind(this) directly to the end of your function definition. You would rewrite your code block as:
setTimeout(function () {
this.setState({ timePassed: true });
}.bind(this), 1000);
Never call setState inside render method
You should never ever call setState inside the render method. Why? calling setState eventually fires the render method again. That means you are calling setState (mentioned in your render block) in a loop that would never end. The correct way to do that is by using componentDidMount hook in React, like so:
class CowtanApp extends Component {
state = {
timePassed: false
}
componentDidMount () {
setTimeout(() => this.setState({timePassed: true}), 1000)
}
render () {
return this.state.timePassed ? (
<NavigatorIOS
style = {styles.container}
initialRoute = {{
component: LoginPage,
title: 'Sign In',
}}/>
) : <LoadingPage/>
}
}
PS Use ternary operators for cleaner, shorter and readable code.
import React, {Component} from 'react';
import {StyleSheet, View, Text} from 'react-native';
class App extends Component {
componentDidMount() {
setTimeout(() => {
this.props.navigation.replace('LoginScreen');
}, 2000);
}
render() {
return (
<View style={styles.MainView}>
<Text>React Native</Text>
</View>
);
}
}
const styles = StyleSheet.create({
MainView: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
export default App;
There looks to be an issue when the time of the phone/emulator is different to the one of the server (where react-native packager is running). In my case there was a 1 minute difference between the time of the phone and the computer. After synchronizing them (didn't do anything fancy, the phone was set on manual time, and I just set it to use the network(sim) provided time), everything worked fine. This github issue helped me find the problem.
Same as above, might help some people.
setTimeout(() => {
if (pushToken!=null && deviceId!=null) {
console.log("pushToken & OS ");
this.setState({ pushToken: pushToken});
this.setState({ deviceId: deviceId });
console.log("pushToken & OS "+pushToken+"\n"+deviceId);
}
}, 1000);