see sharper
see sharper

Reputation: 12025

Best pattern for triggering effects in child components in React

Let's say I have parent and child functional components. The parent wants to trigger some effect such as a focus or resize in the child. For example, I have a generic form component (the child) which includes a submit button, and the parent component, which includes all the non-generic form UI, wants to get the child to focus the submit button.

The problem is that the parent can't directly call the function to focus, so instead I have to set some prop on the child, which, when it changes, tells the child to run the effect. But then the parent has to know when the action has been carried out, so that it can re-set the prop ready for the next time it may need to trigger the effect. This is what I'm doing:

export const Form: FunctionComponent<FormProps> = props => {
  const [focusOkay, setFocusOkay] = useState(false);

  function handleKey(e: React.KeyboardEvent) {
    if (e.key === 'Enter') {
      setFocusOkay(true);
    }
  }

  return (
    <ChildForm
      focussedOkay={() => setFocusOkay(false)}
      focusOkay={focusOkay}
    >
      <input onChange={handleKey} />
    </ChildForm>
  );
};

export const ChildForm: FunctionComponent<ChildProps> = props => {
  const okayBtn = useRef<HTMLButtonElement>();
  useEffect(() => {
    if (props.focusOkay) {
      okayBtn.current.focus();
      if (props.focussedOkay) {
        props.focussedOkay();
      }
    }
  }, [props.focusOkay]);
  return (
    <button ref={okayBtn} >OK </button>
  );
}

This works, but I feel it's ugly, since it requires the use of two props, one for the parent to say "focus the button" and the other for the child to reply "okay I focussed it". Is there a better approach?

Upvotes: 1

Views: 114

Answers (1)

Sujit.Warrier
Sujit.Warrier

Reputation: 2869

I normally set a ref to the element in the child after wrapping the child in forwardRef hoc then call the focus myself from the parent

Upvotes: 1

Related Questions