Reputation: 7715
I have a parent component, <App>
:
constructor() {
super();
this.state = {
transporterPos: 0
}
this.tick = this.tick.bind(this);
}
componentDidMount() {
this.timerId = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this.timerId);
}
tick() {
let transporterPos = this.state.transporterPos;
transporterPos++;
if (transporterPos > 7) {
transporterPos = 0;
}
this.setState({ transporterPos: transporterPos });
}
render() {
return (
<div>
<Staves transporterPos={this.state.transporterPos}/>
</div>
);
}
The <Staves>
component contains several <Stave>
components, each of which contains several <Note>
components. Each <Note>
component is injected with a className
conditional on its active
property being true
:
<div className="noteContainer" onClick={this.handleClick}>
<div className={"note" + (this.props.active ? ' active' : '')}></div>
</div>
handleClick()
is a method that toggles a <Note>
's active
property. I'm not including all the code here to make this more readable. The problem is that when clicking on a <Note>
, although its active
property changes immediately, the styling given by the conditional className
of 'active' is not visible until the component is re-rendered at the next "tick" of the setInterval
method. In other words, rendering only seems to happen once every 1000ms. I would like it to happen immediately. Am I using setInterval
wrong?
Edit:
In response to comments, here is the handleClick
method (in <Note>
):
handleClick() {
this.props.toggleActive(this.props.pos);
}
This calls toggleActive
in <Stave>
:
toggleActive(pos) {
this.props.notes[pos].active = !this.props.notes[pos].active;
}
props.notes
here is part of <App>
's state
, which is passed down to <Stave>
(and which I didn't include in this question for the sake of brevity).
Upvotes: 2
Views: 667
Reputation: 32392
toggleActive(pos) {
this.props.notes[pos].active = !this.props.notes[pos].active;
}
The reason a re-render isn't being triggered is because this.props
is mutated directly instead of with setState
. Move toggleActive
further up to where you can use setState
.
If necessary you can pass the function as a prop to the child component and call it via this.props.toggleActive()
Besides not triggering a re-render, another reason this.props
should never be mutated directly is because your changes will get overwritten whenever the parent changes state and passes props to its children.
Upvotes: 1