I am making a small react app with the help of Potter-API through which users can search for specific characters or spells. After fetching data from the API I am rendering 6 random items(characters/spells) which when clicked lead to a detailed view of the item(characters/spells), I've also added a button called randomize which when clicked renders a new set of random elements.
The issue I am facing is with this 'randomize' button, on clicking it repeatedly what's happening is instead of rendering only 6 elements it starts to render 7, 8,... and breaks at some point resulting in an error.
I'd like to know what's causing this and the fix for this.
class RandomItems extends React.Component {
// this.props.randomNums contain the number of random characters to display
// and the max limit of the items (this.props.data.length) and this.props.subUrl contains
// the detailed-view URL(characters or spells) this.props.data is an array of item objects(characters/spells) out of
// which some characters(some = this.props.randomNums) are chosen and rendered by this component
constructor(props) {
super(props);
this.state = {
itemsList: [],
loading: true
}
this.handleRandoms = this.handleRandoms.bind(this)
}
componentDidMount() {
const items = this.getRandomItems()
this.setState({itemsList: items, loading: false})
}
handleRandoms(){
const items = this.getRandomItems()
this.setState({itemsList: items})
}
getRandomItems() {
function getRandomNumbers(num, limit) {
let randoms = []
for (let i = 0; i < num; i++) {
randoms.push(Math.floor(Math.random() * (limit + 1)))
}
return randoms
}
const randoms = getRandomNumbers(this.props.randomNums, this.props.data.length)
return randoms.map(value => this.props.data[value])
}
// Each of the returned character should be a Link to the detail view of that character
// Using the same component for both the spells/characters page so since the object attributes
// are different for both categories I'm using a prop accessKey that is a string(name/spell) for
// accessing the specific attribute based on the item type(character/spell)
render() {
if (this.state.itemsList && !this.state.loading) {
return (
<div style={{marginTop: '6em'}}>
<h2>Have Some Random {(this.props.subUrl)}!</h2>
<br/>
{this.state.itemsList.map((item, index) => {
return (
<div className={'characterDesign'} key={item._id}>
<Link className={'highlight-link'}
to={`/${this.props.subUrl}/${item._id}`}
>
{(index + 1) + '. ' + item[this.props.accessKey]}
</Link>
</div>
)
})}
<button className={'fill'} onClick={this.handleRandoms}>Randomize!</button>
</div>
)
} else {
return (<h1>Loading...</h1>)
}
}
}
The required array of data objects are sent from the parent component
- After some clicks of the randomize

- After many clicks of the randomize button

PS. I've looked at the array that renders these items and every time it contains exactly 6 elements(even when higher number of elements are being rendered)
{this.state.itemsList.length}in therenderfunction right after the<br/>. I suspect it'll says "7" when it displays 7 characters.