I am developing a tool for running Pen and Paper Campaigns. In this tool I want to be able to display any number of creature entities under one another. They are supposed to be displayed in a certain order.
That order is supposed to be derived from the value of the "ini" of the creatures (i.e. the ones with the highest values get displayed on top). That order is always to be maintained. So when the value changes (since it is contained in an input field) the creature components are supposed to be sorted again.
I have already made the necessary creature components and made a parent component to display them in. But I do not know how to sort them now. I have passed a function from the parent to the children that gets triggered once the value changes. But I do not know how to access the children and sort them based on their state value. I am still quite new to React, so excuse me if this is a trivial thing. I just found no answer anywhere!
I have tried using React.Children.toArray(...)
but that does not seem to be right. I also wanted to try out using refs to save the child components. But I did not really understand how to use them and didn't know how to approach this. Beyond that I am rather clueless.
This is my parent component:
export class Encounter extends React.Component<IEncounterProps,IEncounterState> {
sortByIni(event) {
//somehow trigger something that sorts the creature components
}
addCreature() {
let creature =
<Creature
name={'Ancient Bugbear'}
//I removed other props for the sake of reducing verbosity...
ini={12}
/>;
return creature
}
render(): any {
return (
<div>
{this.addCreature()}
{this.addCreature()}
{this.addCreature()}
</div>
)
}
}
And this is the creature component:
export interface ICreatureProps {
name: string,
ini: number,
//Removing non relevant props for verbosity reducing...
}
export interface ICreatureState {
hitpoints: number
armorclass: number
ini: number
}
export class Creature extends React.Component<ICreatureProps, ICreatureState> {
constructor(props) {
super(props);
this.state= {
hitpoints: this.props.hitpoints || 0,
armorclass: this.props.armorclass || 0,
ini: this.props.ini || 0
};
this.handleIniChange = this.handleIniChange.bind(this);
this.handleACChange = this.handleACChange.bind(this);
this.handleHPChange = this.handleHPChange.bind(this)
}
handleIniChange(event) {
this.setState({ini: event.target.value})
}
handleACChange(event) {
this.setState({armorclass: event.target.value})
}
handleHPChange(event) {
this.setState({hitpoints: event.target.value})
}
render(): any {
return (
<div>
<div className={style.creatureContainer}>
<div className={style.nextToTitleContainer}>
<p className={style.statDisplay}>TP: <input type="number" className={style.inputField} value={this.state.hitpoints} onChange={this.handleHPChange}/></p>
<p className={style.statDisplay}>RK: <input type="number" className={style.inputField} value={this.state.armorclass} onChange={this.handleACChange}/></p>
//This is the field that is supposed to trigger sorting when it changes value
<p className={style.statDisplay}>INI:<input type="number" className={style.inputField} value={this.state.ini} onChange={e=>{this.handleIniChange(e); this.props.sortByIni(e)}}/></p>
</div>
</div>
</div>
)
}
}
This is the supposed outcome when it works. As one sees the creature with the highest value is on top. And of course it is supposed to resort itself whenever a value changes.