skip to Main Content

So I have typescript react project where I want to observe certain child components being viewed, to achieve this I am using IntersectionObserver and refs. In my parent component I have an introduction component imported from another file and I am trying to pass introRef into the component to be used to reference elements in Introduction

introRef = useRef(null)
...
<Introduction ref={introRef} />

My Introduction component is defined as follows:

import React, { forwardRef, LegacyRef } from "react";
import myInfo from "../myInfo.json";


const Introduction = forwardRef<HTMLElement, React.HTMLProps<HTMLElement>>((ref) => {
    return (
      <section ref={ref} className="Introduction">  
          <p className="greeting">Welcome</p>
          <p className="intro">{myInfo.introduction}</p>
          <div className="picture">
          {/* <PixelateToUnpixelate src={myInfo.myPicture} /> */}
          </div>
      </section>
    );
  });
  
  export default Introduction;

on the line : <section ref={ref} className="Introduction"> I am getting the error:
Type ‘HTMLProps’ is not assignable to type ‘LegacyRef | undefined’

To combat the issue I have tried changing the declaration of Introduction to the following

const Introduction = forwardRef((ref:LegacyRef<HTMLElement>) => {
    return (
      <section ref={ref} className="Introduction">  
          <p className="greeting">Welcome</p>
          <p className="intro">{myInfo.introduction}</p>
          <div className="picture">
          {/* <PixelateToUnpixelate src={myInfo.myPicture} /> */}
          </div>
      </section>
    );
  });

The issue here disappeared, but when I try to use the Introduction component in the parent component and pass pass introRef into Introduction I am getting the error:

Type '{ ref: MutableRefObject<null>; }' is not assignable to type 'IntrinsicAttributes & (LegacyRef<HTMLElement> & RefAttributes<unknown>)'.
  Property 'current' is missing in type '{ ref: MutableRefObject<null>; }' but required in type 'RefObject<HTMLElement>'

So again I changed my Introduction component code to:

const Introduction = forwardRef((ref:React.MutableRefObject<null>) => {
    return (
      <section ref={ref} className="Introduction">  
          <p className="greeting">Welcome</p>
          <p className="intro">{myInfo.introduction}</p>
          <div className="picture">
          {/* <PixelateToUnpixelate src={myInfo.myPicture} /> */}
          </div>
      </section>
    );
  });

Now, I am getting this error when I try to pass introRef into Introduction:

Property 'current' is missing in type '{ ref: MutableRefObject<null>; }' but required in type 'MutableRefObject<null>'.

I am out of ideas on how to solve this as from the documentation from React useRef:

current: Initially, it’s set to the initialValue you have passed. You can later set it to something else. If you pass the ref object to React as a ref attribute to a JSX node, React will set its current property.

So I can’t possibly have the current property if I don’t pass the ref object to a ref attribute to a JSX node, in this case Introduction.

I have also tried doing this without wrapping Introduction in forwardRef, similar issues arose.

What am I doing wrong, how do I create a ref and pass it to a child component in typescript React and please provide an explanation, thank you

2

Answers


  1. Chosen as BEST ANSWER

    So, I went back and read the documentation on forwardRefs and in the documentation, it takes two arguments, but in my code I only gave it one. This was the reason that it was not working and throwing the error. the forwardRefs function, takes in props and the ref to be passed down to the children. I came across another post than in the case where no props is needed you can simply use _: unknown as a sort of placeholder.


  2. React 19

    Starting in React 19, you can now access ref as a prop for function components –

    function MyInput({placeholder, ref}) {
      return <input placeholder={placeholder} ref={ref} />
    }
    
    //...
    <MyInput ref={ref} />
    

    React 18

    Supply the types to forwardRef<...>

    type IntroProps = {
      children: R.ReactNode
    }
    
    const Intro = R.forwardRef<HTMLDivElement, IntroProps>((props, ref) => (
      <div
        ref={ref}
        children={props.children}
        style={{
          backgroundColor: "orchid",
          color: "white",
          padding: "1rem",
        }}
      />
    ))
    
    function Foo() {
      const ref = R.useRef<null | HTMLDivElement>(null)
      return <Intro ref={ref}  children="hello world" />
    }
    

    demo on TypeScript playground

    Using React.HTMAttributes<...> will likely be useful to you. This allows you to specify other props your component will receive –

    const Intro = R.forwardRef<HTMLDivElement, R.HTMLAttributes<HTMLDivElement>>(
      (props, ref) => <div ref={ref} children={props.children} />,
    )
    
    function Foo() {
      const ref = R.useRef<null | HTMLDivElement>(null)
      return (
        <Intro
          ref={ref}
          style={{
            backgroundColor: "orchid",
            color: "white",
            padding: "1rem",
          }}
          onClick={event => console.log("ref", ref.current)}
          children="hello world"
        />
      )
    }
    

    demo on TypeScript playground

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search