Search code examples
reactjstypescriptreact-nativereact-functional-componentreact-state

How does one trigger an action in a child functional component in React?


With a basic form/input layout, it's clear that a callback should be used for state changes from child to parent (initiated by child), but how can the parent ask the child component to re-assess its state and communicate that back to parent?

The end goal here is simply to trigger validation of child inputs upon submit of a form button.

Given [ts] code that looks like this:

    const Login : React.FC<Props> = (props) => {
        ...useStates omitted

        const onSubmit = () : void => {
          //trigger `verify()` in PasswordInput to get up-to-date `valid` state var

 
        }
        
        return (
            <PasswordInput
              onValidChange={setValid} />
            <Button
              onPress={submit} />
        )
    }


    const PasswordInput : React.FC<Props> = (props) => {
        ...useStates omitted

        const verify = () => {
          //verify the password value from state

          props.onValidChange(true)
        }


        return (<Input onBlur={verify}/>) 
    }

Notes/paths taken thus far:

UPDATE Lessons learned:

  • If you are going to trigger an action in a child component, you may use the refs method outlined by Nadia below, but the more proper React Way® is probably via a shared Reducer.
  • Don't expect state to always be updated through callbacks to your parent at time of calling into said reference. In my case, the only method ordering that worked was to have what would be the verify method above actually return the up-to-date values.

Solution

  • A simple example of how you can approach this

    function Child(props)
    {
        const validate = () => alert('hi from the child');
        props.registerCallback(validate)
        return (<div>I'm the child</div>)
    }
    
    function Parent()
    {
        const callbackRef = React.useRef();
    
        function registerCallback(callback) {
            callbackRef.current = callback;
        }
        return (
            <div>
                <Child registerCallback={registerCallback} />
                <button onClick={() => callbackRef.current()}>
                    say hello
                </button>
            </div>
        )
    }
    

    https://jsfiddle.net/4howanL2/5/