React: Communication between components

  1. Parent to Child: Props
  2. Child to Parent
    1. Callback Props (advanced props)
    2. Controlled Components
    3. useImperative hook 
  3. Nested Tree: useContext
  4. Sibling: Lift State Up

PARENT TO CHILD: Props

App.jsx

Users.jsx

<User name={user} />

function User({ name }) {

 return <h1> {name} </h1>

}


CHILD TO PARENT

a) Callback Props (Advanced Props)

Parent.jsx

Child1.jsx

export function Parent() {

  function sayHello() {

    alert(“hello triggered”)

  }

  <Child1 onSayHello={sayHello} />

}

function Child1({onSayHello }) {

  return <button onClick={ onSayhello() }>

         Click

      </button>
}


b) Controlled Components

Usually used in forms. Controlled components mean the parent owns the state, the child renders inputs, and every change flows up through callbacks and back down through props.

Parent.jsx

Child1.jsx

import { useState } from "react";

import { Child1 } from "./child1";

 

export function LoginForm() {

    const [email, setEmail] = useState("");

    const [password, setPassword] = useState("");

    function saveForm() {

        console.log(email, password)

    }

    return (

        <>

            <Child1

            onSubmit={saveForm}

            email={email}

            password={password}

            onPasswordChange={setPassword}

            onEmailChange={setEmail}

            />

        </>

    )

}

export function Child1({onSubmit, email, password, onEmailChange, onPasswordChange}) {

    return (

        <>

            <div>

           <input type="text" value={email}

              onChange={(e) => onEmailChange(e.target.value) }/>

 

          <input type="text" value={password}

             onChange={(e)=>onPasswordChange(e.target.value) }/>

 

             <button onClick={() => onSubmit() } >submit</button>

            </div>

        </>

    )

}

c) useImpreative() hook
Used to make the functions from child to be called by the parent directly
Child wraps the "to be exported" function within the useImpreative callback
Parent creates a "ref" to this child component

Example: 
Login page with validation error

Background:
You have a Login page
The email input lives inside a reusable <LoginForm /> child component
The Submit button and error handling logic live in the Parent

Scenario:
User clicks Submit
Parent validates credentials (or API returns error)
Login fails → user should immediately type again
Parent forces focus on the email input inside child (This is where imperative control is needed)|

Why props are awkward here:
You don’t want to pass shouldFocus={true} and manage extra state
Focus is not data, it’s a UI action
Declarative props become noisy

Why useImperativeHandle fits perfectly:
Parent says: “Child, focus now”
Child decides how focus is done
Clean, minimal API

Error → Fix → Cursor goes back automatically
That’s the moment the parent must control focus.

When NOT to use useImpreative:
Data flow
Form submission
Business logic
Anything declarative

Parent

Child (FormInput)


function Parent() {
const inputRef = useRef();
return (
<>
<FormInput ref={inputRef} />

<button onClick={() => inputRef.current.focusInput()}>
        Focus Input
</button>
</>
);
}
const FormInput = forwardRef((props, ref) => {
   const inputRef = useRef();
  useImperativeHandle(ref, () => ({
     focusInput() {
     inputRef.current.focus();
   }
}));
    return <input ref={inputRef} />;
});


3. Use Context

Parent.jsx

Child1.jsx

import { Child1 } from "./child1";

import { createContext } from "react";

 

export const UserContext = createContext()

 

export function LoginForm() {

   const user = { name: 'Stella', type: 'employee' };

 

    return (

        <>

            <UserContext.Provider value={user}>

                <Child1 />

            </UserContext.Provider>

        </>

    )

}

 

import { useContext } from "react";

import {UserContext } from "./parent"

 

export function Child1() {

    const user = useContext(UserContext)

    return (

        <>

            <div>

               hey { user.name }

            </div>

        </>

    )

}

 


4. Lifting the state up

Essentially the same example as "Controlled components" in our 2nd example

Parent holds the state and "lifts" it up — child input updates it via a setter prop, another child reads it.
 

Comments

Popular posts from this blog

Inside the JavaScript Memory Box: Visualizing Variables, References, and Copies

React & State Management: All Concepts