Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

declare type with React.useImperativeHandle()

Tags:

function App(){   const cntEl:any = React.useRef(null);  // I don't know what type should be here.   React.useEffect(()=>{     if(cntEl.current){ cuntEl.current.start() }   }, []);   return <Countdown ref={cntEl} /> } const Countdown = React.forwardRef((props,ref) => {   React.useImperativeHandle(ref, ()=>({     start() {       alert('Start');     }   });   return <div>Countdown</div> });  

I try to use a child method in a parent component using ref and React.useImperativeHandle().

It works well.

but I am not satisfied because of const cntEl:any.

I believe there are many ways to avoid using any type I don't know.

I just need a type that could be replaced type any.

Edited

I can see (property) React.MutableRefObject<null>.current: null when I hover at cntEl.current

like image 669
kyun Avatar asked Jun 05 '20 07:06

kyun


People also ask

What is useImperativeHandle in React?

React useImperativeHandle Hook In React, data is passed from parent to child components via props, known as unidirectional data flow. The parent component cannot directly call a function defined in the child component or reach down to grab a value for itself.

How do you use a memo in React?

Use useMemoThe useMemo Hook accepts a second parameter to declare dependencies. The expensive function will only run when its dependencies have changed. In the following example, the expensive function will only run when count is changed and not when todo's are added.

How do I get past state in React hooks?

While there's currently no React Hook that does this out of the box, you can manually retrieve either the previous state or props from within a functional component by leveraging the useRef , useState , usePrevious , and useEffect Hooks in React.


2 Answers

I recommend you use type definitions more explicitly

For example, with React DT, you can define ref exotic component with ForwardRefRenderFunction instead of FC.

type CountdownProps = {}      type CountdownHandle = {   start: () => void, }      const Countdown: React.ForwardRefRenderFunction<CountdownHandle, CountdownProps> = (   props,   forwardedRef, ) => {   React.useImperativeHandle(forwardedRef, ()=>({     start() {       alert('Start');     }   });    return <div>Countdown</div>; }  export default React.forwardRef(Countdown); 

and then use React utility ElementRef, TypeScript can infer exact ref type of your component

const App: React.FC = () => {   // this will be inferred as `CountdownHandle`   type CountdownHandle = React.ElementRef<typeof Countdown>;    const ref = React.useRef<CountdownHandle>(null); // assign null makes it compatible with elements.    return (     <Countdown ref={ref} />   ); }; 
like image 158
Hyeseong Avatar answered Oct 25 '22 15:10

Hyeseong


The accepted answer is overcomplicated, you just need to declare a CountdownHandle type.

For me it'll go like this:

// Countdown.tsx  export type CountdownHandle = {   start: () => void; };  type Props = {};  const Countdown = React.forwardRef<CountdownHandle, Props>((props, ref) => {   React.useImperativeHandle(ref, () => ({     // start() has type inferrence here     start() {       alert('Start');     },   }));    return <div>Countdown</div>; }); 
// The component uses the Countdown component  import Countdown, { CountdownHandle } from "./Countdown.tsx";  function App() {   const countdownEl = React.useRef<CountdownHandle>(null);    React.useEffect(() => {     if (countdownEl.current) {       // start() has type inferrence here as well       countdownEl.current.start();     }   }, []);    return <Countdown ref={countdownEl} />; } 
like image 24
Loi Nguyen Huynh Avatar answered Oct 25 '22 13:10

Loi Nguyen Huynh