Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Real Life Example - UseImperativeHandle
Daniel Bellmas
Daniel Bellmas

Posted on • Edited on

     

Real Life Example - UseImperativeHandle

1. Wait wait...what is it?

useImperativeHandle allows us topass values and functions from aChild component to aParent using aref.
From there, the Parent can either use it itself or pass it to another Child.

Note that you can only pass a ref as a prop to a child that wraps its component inforwardRef.


Code examples are much better than words when it comes to understanding so here is one:

// Parent ComponentconstApp=()=>{constref=useRef();return(<div><ComponentWithButtonref={ref}/><buttononClick={()=>ref.current.increment()}>another button</button></div>);};// Child ComponentconstComponentWithButton=forwardRef((props,ref)=>{useImperativeHandle(ref,()=>({increment}))const[count,setCount]=useState(0);constincrement=()=>setCount(count+1);return(<div><buttononClick={increment}>click</button><h2>Count:{count}</h2></div>)})
Enter fullscreen modeExit fullscreen mode

In the example above, we are changing the count variable in the parent component with the help ofuseImperativeHandle andforwardRef.

2. Why?

The general pattern in React is to have aunidirectional flow of data.
In cases wherebidirectional dataflow is needed, we can use libraries such asRedux orReact context.

However, in some cases, using those is simply just overkill.
This is whereuseImperativeHandle comes in.


Now that we have some understanding of the hook and when we want to use it let's move to the Real Life Example...

We have aSettings page that allows the user to update and edit his information and notification preferences.

The component hassections and every section is a form that is responsible for changing data related to the user (A section for his profile info, his privacy settings, and his notifications settings).

constSection=({name,text,fields,schema})=>{const{control,handleSubmit,reset,formState}=useForm({mode:'onChange',defaultValues:fields.reduce((acc,field)=>({...acc,[field.name]:field.defaultValue}),{})});return(<sectionclassName={styles.section}><Titletext={text}/><formonSubmit={handleSubmit(onSubmit)}>{fields.map(field=>(<Fieldkey={field.name}{...field}control={control}/>))}</form></section>);};
Enter fullscreen modeExit fullscreen mode

Everysection is rendered in theSettings component - The Parent Component:

constSettings=()=>(<mainclassName={styles.main}>{SECTIONS.map(section=>(<Sectionkey={section.name}{...section}/>))}</main>);
Enter fullscreen modeExit fullscreen mode

Supposedly, everything is fine a Parent component that renders children...but what happens when we want to trigger the submit function of every section by clicking a global button?
We will need some way to allow the parent to control, that's whereuseImperativeHandle comes in.

We will add the hook in theSection component and wrap it with the forward ref so that we can pass a ref fromSettings:

constSection=React.forwardRef(({name,text,fields,schema},ref)=>{const{control,handleSubmit,reset,formState}=useForm({mode:'onChange',defaultValues:fields.reduce((acc,field)=>({...acc,[field.name]:field.defaultValue}),{})});useImperativeHandle(ref,()=>({submit(){handleSubmit(onSubmit)();}}));return(<sectionclassName={styles.section}><Titletext={text}/><formonSubmit={handleSubmit(onSubmit)}>{fields.map(field=>(<Fieldkey={field.name}{...field}control={control}/>))}</form></section>);});
Enter fullscreen modeExit fullscreen mode

With the help of the hook we are able to create some sort of an API for the parent to use, in this example we are exposing thesubmit() function that we we'll be able to call.

Now ourSettings component will look like so:

constSettings=()=>{constrefProfile=useRef();constrefNotifications=useRef();constrefPrivacy=useRef();// The SECTIONS object is a configuration object that will// hold the refs among the rest of the dataconstonSubmitAll=()=>{SECTIONS.forEach(({ref})=>{ref.current.submit();});};return(<mainclassName={styles.main}>{SECTIONS.map(section=>(// The ref of each section i passed here in the spread// operation.<Sectionkey={section.name}{...section}/>))}</main>);}
Enter fullscreen modeExit fullscreen mode

That's it! We did it!
We Passed the control back to the parent without importing or using a more complex library.

We Did It


3. Conclusion

I don't mean to disappoint but React doesn’t recommend using this hook. (there will most likely be another way in which you can do this without using the hook.)

Full disclosure, I ended up changing the component structure
But! nonetheless, it was super fun learning about this mysterious hook that is rarely used.

I hope you had fun too 🙏🏼 Thank you for reading!!

Well that was fun

Top comments(6)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
danacoding profile image
DanaCoding
  • Joined

I don't quite agree with your comparison of Ref and Redux. Because my understanding is that Ref is more to operate on the HTML DOM.

CollapseExpand
 
danielbellmas profile image
Daniel Bellmas
Full-Stack Developer
  • Joined

Yes usuallyuseRef is used for DOM nodes but in this case (with the help offorwardRefanduseImerativeHandle) we are able to create some sort of an API the parent can use, much like the global functions and state Redux gives us.

If you want to read more I found this link:reactjs.org/docs/refs-and-the-dom....

CollapseExpand
 
yarivshamash profile image
Yariv Shamash
🌱 My journey: From marine scientist to web developer🛠️ Skills: React.js, Next.js, TypeScript, WebRTC, Node.js, Firebase🌍 Passion: Creating technology that positively impacts people and the planet
  • Location
    Israel
  • Education
    M. Sc.
  • Work
    Front end develper
  • Joined

Great read!
Even though it is advised against and I will probably not use it in my career. Reading of your journey with the task was nice and very relatable :)

CollapseExpand
 
danielbellmas profile image
Daniel Bellmas
Full-Stack Developer
  • Joined

Thank you Yariv!!

CollapseExpand
 
1chris_alex profile image
Christian Alexsander
Developer, gamer who love create with code.
  • Location
    Belo Horizonte
  • Work
    Fullstack developer at Dti Digital
  • Joined

Can you show a typescript'sref correctly typed foruseImperativeHandle?

CollapseExpand
 
danielbellmas profile image
Daniel Bellmas
Full-Stack Developer
  • Joined

Theref's type will be:
React.Ref<{ submit(): void }>
for more information check out this site:react-typescript-cheatsheet.netlif...

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Full-Stack Developer
  • Joined

More fromDaniel Bellmas

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp