Manipulate child state from parent in React.

Manipulate child state from parent in React.

Using refs we can invoke methods of child components from a parent in both class components as well as in functional components. This is just a workaround, recommended way is to lift the state up to the parent and then pass it through props to the child component or with context API.

Let’s use a simple example of a counter.

import React, { useState } from "react";

const Child = () => {
const [count, setCount] = useState(0);

return <div>Child counter {count}</div>;
};

export default Child;

And our Parent component looks like this where it has a button and renders the child component as well.

const Parent = () => {
const handleUpdate = () => {};
    return (
        <div>
        <h1>Parent</h1>
        <button onClick={handleUpdate}> Update Count </button>
        </div>
    );
};

App UI

Now on the button click we want to increase the count in the child component. We can do this using refs. Let’s modify our child component first.

const Child = forwardRef((props, ref) => {
    const [count, setCount] = useState(0);

    useImperativeHandle(ref, () => ({
        handleInc() {
            setCount(count + 1);
        }
    }));

    return <div>Child counter {count}</div>;
});

export default Child;

React.forwardRef creates a React component that forwards the ref attribute it receives to another component below in the tree.

useImperativeHandle customizes the instance value that is exposed to parent components when using ref. As always, imperative code using refs should be avoided in most cases. useImperativeHandle should be used with [forwardRef](https://reactjs.org/docs/react-api.html#reactforwardref)

Now in the parent component, we just have to create a ref and pass it to the child component as props.

const Parent = () => {
const childRef = createRef();

return (
    <div>
    <h1>Parent</h1>
    <Child ref={childRef} />
    <button onClick={() => childRef.current.handleInc()}>Update Count</button>
    </div>
   );
};

And it’s done.

Another pattern with class components we can use this in child components.

class Child extends Component {
    constructor() {
        super();
        this.state = {
            count: 0
        };
        this.handleInc = this.handleInc.bind(this);
    }
    handleInc() {
        this.setState({ count: this.state.count + 1 });
    }
    render() {
        return <div>Count: {this.state.count}</div>;
    }
}

If you want to play around https://codesandbox.io/s/silly-montalcini-1iimot