Reputation: 22668
I am writing a Box component which
I wrote this component and it works fine.
Now I would like to improve my component. I need to show multiply Box on my parent page and when I click on one Box I would like to reset the state of the rest Box components displays on parent so when I move mouse between the Boxes their styles need to be change and when I click one of them then the selected Box's border needs to be change.
This is the Box component:
const STYLE = {
boxMouseOver: {...},
boxMouseOut: {...},
boxOn: {...},
}
export default class ClickableBox extends React.Component {
constructor (props) {
super(props)
this.state = {
mouseOver: false,
turnOn: false
}
}
handleMouseOver = () => {
this.setState({
mouseOver: true
})
}
handleMouseOut = () => {
this.setState({
mouseOver: false
})
}
handleOnClick = () => {
this.setState({
turnOn: !this.state.turnOn
});
this.props.resetStateCallback();
}
resetState = () = => {
this.setState({
turnOn: false
});
}
render () {
let style = this.state.mouseOver ? STYLE.boxMouseOver : STYLE.boxMouseOut
style = this.state.turnOn ? STYLE.boxOn : style
return (
<div style={style} onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut} onClick={this.handleOnClick}>
<span style={STYLE.title}>{this.props.title}</span>
<br/>{this.state.turnOn ? "on" : "off"}
</div>
)
}
}
And this is the parent component:
export default class GroupOfBoxes extends React.Component {
reset () {
alert('reset')
// **** I need help for this part ****
// Need to be called resetState() method on
// ClickableBox components shows on this page
for (currentBox : ?????) {
if (currentBox != selected Box??) {
currentBox.resetState()
}
}
}
render () {
return (
<div>
<Grid>
<Row className='show-grid'>
<Col sm={12}>
<ClickableBox title='1' resetStateCallback={this.reset} />
<ClickableBox title='2' resetStateCallback={this.reset} />
<ClickableBox title='3' resetStateCallback={this.reset} />
<ClickableBox title='4' resetStateCallback={this.reset} />
</Col>
</Row>
<Row className='show-grid'>
<Col sm={12}>
<ClickableBox title='5' resetStateCallback={this.reset} />
<ClickableBox title='6' resetStateCallback={this.reset} />
<ClickableBox title='7' resetStateCallback={this.reset} />
<ClickableBox title='8' resetStateCallback={this.reset} />
</Col>
</Row>
</Grid>
</div>
)
}
}
I do not know hot to change the Box component state from the parent page because I need to have references of my Box components on the parent page and call ClickableBox.resetState()
method on each ClickableBox
components from the GroupOfBoxes.reset()
method.
---- UPDATE ----
After I read more React related docs I was able to make my code works but I think that my solution is far from the optimal. I would appreciate any help for optimalisation.
So I use ref
property to get references to the my Box components and I wrote lots of conditions to decide which Box components need to be reset:
First, I made change on the ClickableBox component, I added a 'this' param to the resetStateCallback method call:
handleOnClick = () => {
this.setState({
turnOn: !this.state.turnOn
});
this.props.resetStateCallback(this);
}
Then I added the ref keys to the parent component:
<ClickableBox ref='box1' title='1' body='...' footer='...' resetStateCallback={this.reset} />
<ClickableBox ref='box2' title='2' body='...' footer='...' resetStateCallback={this.reset} />
...
Finally I modified the reset() method on parent component:
(this method looks so ugly so please help me to optimalize it if you can)
reset(comp) {
if (comp.props.title === '1') {
this.refs.box2.resetState()
this.refs.box3.resetState()
this.refs.box4.resetState()
this.refs.box5.resetState()
this.refs.box6.resetState()
this.refs.box7.resetState()
this.refs.box8.resetState()
} else if (comp.props.title === '2') {
this.refs.box1.resetState()
this.refs.box3.resetState()
this.refs.box4.resetState()
this.refs.box5.resetState()
this.refs.box6.resetState()
this.refs.box7.resetState()
this.refs.box8.resetState()
} else if (comp.props.title === '3') {
this.refs.box1.resetState()
this.refs.box2.resetState()
this.refs.box4.resetState()
this.refs.box5.resetState()
this.refs.box6.resetState()
this.refs.box7.resetState()
this.refs.box8.resetState()
} else if (comp.props.title === '4') {
...
} else if (comp.props.title === '5') {
...
} else if (comp.props.title === '6') {
...
} else if (comp.props.title === '7') {
...
} else if (comp.props.title === '8') {
...
}
}
Upvotes: 2
Views: 132
Reputation: 2638
I would wrap all the boxes inside BoxWrapper
. BoxWrapper has two properties in its state: mouseOverIndex
and clickedIndex
.
It passes this state down to its children. That way, all the logic is held in the wrapper, and Box
does not need to know of the state of its siblings.
See https://jsfiddle.net/20kpgjcj/3/
Upvotes: 0