React: Communication between components
- Parent to Child: Props
- Child to Parent
- Callback Props (advanced props)
- Controlled Components
- useImperative hook
- Nested Tree: useContext
- 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
That’s the moment the parent must control focus.
When NOT to use useImpreative:
|
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 exampleParent holds the state and "lifts" it up — child input updates it via a setter prop, another child reads it.
Comments
Post a Comment