Finishing Up
Right now we have some good things, and some bad things. Addressing the bad things should make the good things even better. So let's keep going.
The main bad things are:
- using
setInterval
inside ourrender
method - not using the output of
this.determineNextColourCombo()
- we're not applying the CSS changes anywhere anyway
Let's start with the big issue: using setInterval
inside our render
method.
The React docs give us a better approach to this problem.
Let's use the React component lifecycle approach to address this issue:
+ public componentDidMount() {
+ this.interval = setInterval(() => this.updateGradient(), 1000);
+ }
+
+ public componentWillUnmount() {
+ clearInterval(this.interval);
+ }
public render() {
this.determineNextColourCombo();
- setInterval(this.updateGradient.bind(this),2000);
return (
<div className="AnimatedBackground">
hello
</div>
);
}
TypeScript isn't happy about us using this undefined interval
property.
Now, this property doesn't need to be on the state
in my opinion. It's a purely internal concept. I'm going to define a private
class property for this instead.
private interval: any;
Wrap Up And Display
All the hard work is now done.
What we now need is the two interesting RGB values, which we can then use to create the next background
attribute to apply to our div
.
public render() {
const nextColourCombo = this.determineNextColourCombo();
const css = {
background:"-moz-linear-gradient(left, "+nextColourCombo[0]+" 0%, "+nextColourCombo[1]+" 100%)"
};
return (
<div className="AnimatedBackground" style={css}>hello</div>
);
}
Two Bugs
There are, unfortunately, two rather pesky little bugs to contend with.
The cause of the first is something of a guess. Here's the code:
this.setState({
step: step + gradientSpeed
});
console.log('step',step );
if ( this.state.step >= 1 )
{
// etc
I believe, but am not sure how to reliably evidence, that using this.state.step
after previously changing the state of step
with this.setState
is the cause of the problem.
We can fix this bug by using the destructured step
rather than this.state.step
in the conditional:
- if ( this.state.step >= 1 )
+ if ( step >= 1 )
{
And that seems to fix that.
The second bug is a bit more tricky.
Watch the video for a better understanding of the exact problem. It's a visual thing. We see a 'flicker' when the conditional is triggered.
Again, my solution to this is a guess as to why this works.
if ( step >= 1 )
{
- this.setState({
- step: step % 1
- });
this.state.colourIndices[0] = this.state.colourIndices[1];
this.state.colourIndices[2] = this.state.colourIndices[3];
// pick two new target colour indices
// do not pick the same as the current one
this.state.colourIndices[1] = ( this.state.colourIndices[1] + Math.floor( 1 + Math.random() * (colours.length - 1))) % colours.length;
this.state.colourIndices[3] = ( this.state.colourIndices[3] + Math.floor( 1 + Math.random() * (colours.length - 1))) % colours.length;
+ this.setState({
+ step: step % 1
+ });
}
Simply moving the second update of the component's state
to after the logic has been evaluated 'fixes' the problem. My best guess here is that there's a momentary delay - the flicker - whilst the rest of the computation happens.
By shifting the second call of this.setState
to after the logic is evaluated, we get a much smoother experience.
And that's it. We have migrated Mario Klingemann's code to TypeScript.
As mentioned right at the start of this tutorial, a possibly preferable solution to this problem is to use CSS3 transitions / animations instead. That said, I hope you found this process useful, and that you fall in love with TypeScript, as I have.