Reputation: 291
I have a bootstrap table with images and names. My data is an array of objects containing image URLs and names. When I click the button I want the image objects to shuffle every 1 second. I am using the Fisher-Yates algorithm to shuffle inside of a setInterval() function.
I would also like to know how to create a stop button.
mock-data:
export const data = [{
url: 'https://via.placeholder.com/80/FF0000',
name: 'ben'
},
{
url: 'https://via.placeholder.com/80/000000',
name: 'jon'
},
{
url: 'https://via.placeholder.com/80/FFFFFF',
name: 'sam'
},
{
url: 'https://via.placeholder.com/80/0000FF',
name: 'bill'
},
{
url: 'https://via.placeholder.com/80/008000',
name: 'tom'
}
];
Here is my Component:
import React, { Component } from 'react';
import { Table, Button } from 'reactstrap';
import './App.css';
import { data } from './mock-data';
import { shuffle } from './helpers/shuffle';
class App extends Component {
constructor(props){
super(props)
this.state = {
images: data
}
}
handleStartShuffle = () => {
this.setState({images: setInterval(shuffle(this.state.images), 1000)});
}
render () {
const imageTable = this.state.images.map((item, index) => {
console.log('item.url', item.url)
return (
<tr key={index}>
<td>
<img src={item.url} alt='random' />
</td>
<td>{item.name}</td>
</tr>
)
})
return (
<div>
<Table>
<thead>
<tr>
<th>image</th>
<th>name</th>
</tr>
</thead>
<tbody>
{imageTable}
</tbody>
</Table>
<Button onClick={this.handleStartShuffle}>Start</Button>
</div>
);
}
}
export default App;
Here is my helper function for shuffling:
export function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * i);
const temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
Upvotes: 2
Views: 771
Reputation: 11328
@TShort already showed you exactly how to keep track of the interval and stop it properly, so I'm not going to copy/paste that here.
But, your shuffle function is currently modifying the array in-place. Since the array is in your component's state, this can lead to unpredictable results. You'll want to change your function to return a new array.
The simplest solution is to make a copy at the start of the function:
export function shuffle(oldArray) {
const array = [...oldArray];
Upvotes: 1
Reputation: 1343
setInterval returns a timer id, then you can call to clearInterval with that id. You example is a little blurry, specially when you store the interval id in state.images. See Using setInterval in React Component
Upvotes: 0
Reputation: 3614
I would do it like this:
let interval;
handleStartShuffle = () => {
interval = setInterval(() => {
this.setState({images: shuffle(this.state.images)});
}, 1000);
}
stopShuffle = () => {
if(interval) {
clearInterval(interval);
}
}
Upvotes: 2