Reputation:
I want to iterate (using setIterval
) an an array of string like that:
const colors = ['all', 'red', 'blue', 'green', 'yellow']
The result is:
console.log('all')
console.log('red') // after 20 sec
console.log('blue') // after 10 sec
console.log('green') // after 10 sec
console.log('yellow') // after 10 sec
But I have to consider also a random number: during the iteration, I may or may not want to show that color (this is related to single color (red
, blue
, green
, yellow
) not all
).
This depends on a certain condition that we can consider a random number in this simplified example:
if(Math.random() >= 0.5)
showTheColor
else
doesntShowTheColor
I simulate an example:
start animation
show color all for 20 seconds
coin throw for color red = 0.7
show color red for 10 seconds
coin throw for color blue = 0.4
/
coin throw for color green = 0.1
/
coin throw for color yellow = 0.8
show color yellow for 10 seconds
show color all for 20 seconds
coin throw for color red = 0.2
/
coin throw for color blue = 0.3
/
coin throw for color green = 0.78
show color green for 10 seconds
coin throw for color yellow = 0.5
show color yellow for 10 seconds
show color all for 20 seconds
coin throw for color red = 0.6
show color red for 10 seconds
coin throw for color blue = 0.7
show color blue for 10 seconds
coin throw for color green = 0.4
/
coin throw for color yellow = 0.1
/
show color all for 20 seconds
coin throw for color red = 0.2
/
coin throw for color blue = 0.1
/
coin throw for color green = 0.3
/
coin throw for color yellow = 0.15
/
// NB: doesn't show color all for 20 seconds because all the previous colors are null. If I showed all for 20 sec, I would have a total of 40 sec of all and that's not what I want
coin throw for color red = 0.5
show color red for 10 seconds
Here is a piece of my code:
const INTERVAL_ALL = 20 // sec
const INTERVAL_SINGLE = 10 // sec
export class Animation extends React.Component {
interval = null
i = -1
colors: string[]
async componentDidMount() {
this.colors = ['all', 'red', 'blue', 'green', 'yellow']
this.startPlaying()
}
startPlaying = () => {
this.interval = window.setInterval(() => this.updateColor(), INTERVAL * 1000) // which interval?
}
// where do I put conditions and how?
updateColor() {
this.i = this.i === this.colors.length - 1 ? 0 : this.i + 1
const color = this.colors[this.i]
this.doSomethingWithColor(color)
}
componentWillUnmount() {
clearInterval(this.interval)
}
doSomethingWithColor(color) {
console.log(color)
}
render() {
return (...)
}
}
The code is a simplified version, it doesn't take into account the different types of timing and conditions. I need help
Thanks a lot
Upvotes: 1
Views: 415
Reputation: 15688
possibly you're looking for something like this:
Keeping it relatively simply, here's a sandbox as well: https://codesandbox.io/s/gallant-bardeen-7rxmh
class App extends React.Component {
state = {
colors: ["red", "orange", "yellow", "green", "blue"],
currentColor: "red",
currentIndex: 0,
colorWasSkipped: false
};
componentDidMount() {
this.changeColor();
}
componentDidUpdate() {
const { currentIndex, colorWasSkipped } = this.state;
setTimeout(
() => {
this.changeColor();
},
currentIndex === 0 && !colorWasSkipped
? "20000"
: colorWasSkipped
? 0
: "10000"
);
}
changeColor = () => {
const { colors, currentIndex } = this.state;
const randomNumber = Math.random();
const newColor =
currentIndex < colors.length - 1 ? colors[currentIndex + 1] : colors[0];
const newIndex = currentIndex < colors.length - 1 ? currentIndex + 1 : 0;
if (randomNumber >= 0.5) {
console.log(randomNumber + " changed " + newColor);
this.setState({
currentColor: newColor,
currentIndex: newIndex,
colorWasSkipped: false
});
} else {
console.log(randomNumber + " skip " + newColor);
this.setState({
currentIndex: newIndex,
colorWasSkipped: true
});
}
};
render() {
const color = this.state.currentColor;
return <div style={{ height: "200px", background: `${color}` }} />;
}
}
Let me know if you have any questions. If a color is skipped, we immediately try a new color and if its random number is less than 0.5, we skip it as well. The cycle continues until we get a number greater than or equal to 0.5, then we display that color for 10 seconds, unless we are back at index 0, where we display that color for 20 seconds instead.
Upvotes: 1
Reputation: 364
I am not a React guy per se, but let me know if this is what you are looking for. Also, you did not mention what the behaviour should be if after a coin toss nothing should happen - should we toss the coin once more right away or should we still wait for the interval?
const INTERVAL_ALL = 20 // sec
const INTERVAL_SINGLE = 10 // sec
export class Animation extends React.Component {
// interval = null - not needed, timeout will do
activeInterval: number;
i = 1 // should start at index 1, right after 'all'
colors: string[]
currentColor: string;
async componentDidMount() {
this.colors = ['all', 'red', 'blue', 'green', 'yellow']
this.currentColor = this.colors[0] // set current color to 'all' at beginning
this.activeInterval = INTERVAL_ALL; // animation starts with all, so 20 secs.
this.startPlaying();
}
startPlaying = () => {
setTimeout(() => {
this.attemptColorChange();
}, this.activeInterval * 1000) //
}
// where do I put conditions and how?
pickNewColor(): string {
this.i = this.i % this.colors.length
const newColor = this.colors[this.i++]
return newColor;
}
componentWillUnmount() {
// clearInterval(this.interval)
}
attemptColorChange() {
const newColor = this.pickNewColor();
const shouldChangeColor = Math.random() >= 0.5
if (shouldChangeColor) {
if (newColor === 'all') {
this.activeInterval = INTERVAL_ALL;
} else {
this.activeInterval = INTERVAL_SINGLE;
}
this.currentColor = newColor;
this.startPlaying();
}
else {
this.attemptColorChange();
}
}
render() {
}
}
Upvotes: 0