Reputation: 11270
Let's say I have three elements that hold in state a counter that increments when clicked.
If I click on one element, how do I reset the other counters to 0?
https://jsfiddle.net/69z2wepo/56827
const Parent = React.createClass({
render() {
const rows = [];
for (let i = 0; i < 3; i++) {
rows.push(<Child key={i} />);
}
return (
<ul>
{rows}
</ul>
);
}
});
const Child = React.createClass({
getInitialState() {
return {counter: 0};
},
handleClick() {
this.setState({counter: ++this.state.counter });
},
render() {
return (
<div onClick={this.handleClick}>
{this.state.counter}
</div>
);
}
});
ReactDOM.render(
<Parent />,
document.getElementById('app')
);
Upvotes: 15
Views: 18285
Reputation: 173
const Parent = () => {
let clearFunc = null; // child clear state function will be stored in this variable
// in parent component, call this clearChild function.
const clearChild = () => {
typeof childClearFunc === 'function' && childClearFunc();
}
return <Child handleClear={(func) => clearFunc = func } />
}
const Child = () => {
const handleClear = () => {
// code to clear everything in child
};
if (props.handleClear) {
props.handleClear(handleClear);
}
}
Upvotes: 0
Reputation: 2858
It you really can't lift the state into the parent component as other answers have suggested, a hacky way to do this is to just change the key
prop of an element. This causes React to unmount the element with the old key
and mount a new instance.
class ChildComponent extends React.Component {
state = {
count: 0
};
render() {
const { count } = this.state;
return (
<div>
<div>count: {count}</div>
<button onClick={() => this.setState({ count: count + 1 })}>Increment</button>
</div>
);
}
}
class ParentComponent extends React.Component {
state = {
stateBustingKey: 0
};
render() {
const { stateBustingKey } = this.state;
return (
<div>
<ChildComponent key={stateBustingKey} />
<button
onClick={() =>
this.setState({ stateBustingKey: stateBustingKey + 1 })
}
>
Reset
</button>
</div>
);
}
}
ReactDOM.render(<ParentComponent />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root" />
Upvotes: 33
Reputation: 2709
Component parent
in this case should be managed the state of children
.
Check this:
const Parent = React.createClass({
getInitialState() {
return {counter: 0, id: 0};
},
handleClick(id) {
if(this.state.id == id){
this.setState({counter: ++this.state.counter, id: id });
} else {
this.setState({counter: 1, id: id });
}
},
getCounter(id){
if(id == this.state.id){
return this.state.counter;
} else {
return 0;
}
},
render() {
const rows = [];
for (let i = 0; i < 3; i++) {
rows.push(<Child key={i} counter={this.getCounter(i)} handleClick={this.handleClick} id={i} />);
}
return (
<ul>
{rows}
</ul>
);
}
});
const Child = React.createClass({
render() {
return (
<div onClick={this.props.handleClick.bind(null, this.props.id)}>
{this.props.counter}
</div>
);
}
});
ReactDOM.render(
<Parent />,
document.getElementById('app')
);
Upvotes: 3
Reputation: 28397
That would be a little hard since your Child
components are managing their own state.
You can convert them into dumb components and manage their state in your Parent
component.
Something like this
const Parent = React.createClass({
getInitialState() {
return {counters: [0,0,0]};
},
handleClick(index){
let newCounterState = this.state.counters.map(() => 0);
newCounterState[index] = this.state.counters[index] + 1 ;
this.setState({counters : newCounterState})
},
render() {
const rows = this.state.counters.map((value,index) => (
<Child
key={index}
handleClick={() => this.handleClick(index)}
counter={value}
/>
))
return (
<ul>
{rows}
</ul>
);
}
});
const Child = ({counter,handleClick}) => (
<div onClick={handleClick}>
{counter}
</div>
)
ReactDOM.render(
<Parent />,
document.getElementById('app')
);
Upvotes: 5