Controlling Child Component State from a Parent in React

Controlling Child Component State from a Parent in React

Today I stumbled into a fun little React problem while working with forwardRef and useImperativeHandle. I had a simple input component that needed to expose some methods—like .focus() and .clear()—to the parent. Easy enough, right?

But then I hit the next question: "Wait… what if I want the parent to access or update the internal state of this child?"

Here’s how it started:

import React, { forwardRef, useImperativeHandle, useRef } from 'react';

const MyInput = forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus(),
    clear: () => { inputRef.current.value = ''; },
  }));

  return <input ref={inputRef} />;
});
        

Pretty straightforward. But I realized this input isn't even using React state—it's just directly manipulating the DOM. So what if we want to store the input’s value in a state and give the parent full control over it?

🧠 Solution: Expose state methods with useImperativeHandle

React doesn’t allow parents to directly "see" into a child’s state (for good reason!), but we can selectively expose getters and setters through the ref.

Here’s how that looks:

import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react';

const MyInput = forwardRef((props, ref) => {
  const [value, setValue] = useState('');
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus(),
    clear: () => setValue(''),
    getValue: () => value,
    setValue: (val) => setValue(val),
  }));

  return (
    <input
      ref={inputRef}
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  );
});
        

Now in the parent, we can do this:

const Parent = () => {
  const inputRef = useRef();

  return (
    <>
      <MyInput ref={inputRef} />
      <button onClick={() => inputRef.current.focus()}>Focus</button>
      <button onClick={() => inputRef.current.clear()}>Clear</button>
      <button onClick={() => alert(inputRef.current.getValue())}>Get Value</button>
      <button onClick={() => inputRef.current.setValue('Updated from parent!')}>Set Value</button>
    </>
  );
};
        

💡 Takeaway

useImperativeHandle isn’t just for DOM access—it's your window into exposing custom logic or controlled state from a child to a parent, without breaking the encapsulation React gives you by default.

This pattern comes in handy when you're working with reusable input components, modals, or anything that needs to be controlled externally in a more declarative React-style way.


#React #JavaScript #FrontendDevelopment #radikadilanka #TodayILearned

farhan ahzan

Associate Software Engineer at TWC Innovations | Full Stack Developer | React | Next | Node | Python | Typescript | WordPress

3w

Definitely worth reading

To view or add a comment, sign in

More articles by Radika Dilanka

Insights from the community

Others also viewed

Explore topics