React: Update Child Component Without Rerendering Parent
When you want to update a child without updating the parent, the state must be in the child. You can pass the state getter / setter from the child to the parent to be able to read and update it:
function Child({onMount}) {
const [value, setValue] = useState(0);
useEffect(() => {
onMount([value, setValue]);
}, [onMount, value]);
return (
<div>
{value}
</div>
);
};
function Parent() {
let value = null;
let setValue = null;
const onChildMount = (dataFromChild) => {
value = dataFromChild[0];
setValue = dataFromChild[1];
};
// Call setValue to update child without updating parent
return (
<div>
<Child onMount={onChildMount}/>
</div>
);
};
Since const [value, setValue] = useState(0);
is in the Child
, only the child component will re render when updating the value. Additionally, since the Parent
receives value
and setValue
at onChildMount
, the parent can use them to update the child without re rendering the parent.
It is not possible what you want. To pass a prop to a child component, the parent component's state or props should change somehow. As you know, this triggers a re-render obviously, so all the children re-render. To be updated, your Clock
component should be re-rendered and unmounted/remounted in this situation to reflect the DOM change.
If your app is not so big and doesn't have so many children do not struggle with this problem since rendering is not so expensive. The expensive one is DOM manipulation of a component. Here, React diffs the real and virtual DOM and do not unmount/remount Label
component even it re-renders. But, if you write your Label
component as a PureComponent
it doesn't re-render. But for Clock
component to be updated like this, there is no way.
class Label extends React.PureComponent {
render() {
console.log("rendered");
return (<p>{this.props.text}</p>)
}
}
const Clock = ({ date }) => (
<div>{date.toLocaleTimeString()}</div>
)
class App extends React.Component {
constructor() {
super()
this.state = {
date: new Date()
}
}
componentWillMount() {
this.interval = setInterval(
() => this.setState({ date: new Date() }),
1000
)
}
componentWillUnmount() {
clearInterval(this.interval)
}
updateTime() {
}
render() {
return (
<div>
<Label text="The current time is:" />
<Clock date={this.state.date} />
</div>
)
}
}