Home > Software engineering >  How to pass a generic to a React component and use that generic within the component
How to pass a generic to a React component and use that generic within the component

Time:06-30

I'm building an input component that takes a displayName that is a string and a value that should be a generic. It also takes a function as a prop that needs to fire and handle that generic value when the input is changed.

So, let's say MyInterfaceXYZ holds the displayName and value like so:

interface MyInterfaceXYZ<T> {
    displayName: string
    value: T
}

We then want this generic value to be used in our main props interface that wraps our first interface... Like the one below (but my syntax is wrong I think):

interface MyComponentProps<T> {
    myFunctionThatTakesMyGeneric: (value: T) => void
    options: MyInterfaceXYZ<T>[]
}

We then want to pass use this as our props in our react component - where we will receive a generic from an onChange listener.

// The syntax on the line below is totally invalid
const InputSelect: React.FC<MyComponentProps<T>> = ({
    myFunctionThatTakesMyGeneric,
    options,
}) => {

    // `<T extends MyInterfaceXYZ>` requires 1 argument 
    // that I don't know how to pass here
    function onChangeHandler<T extends MyInterfaceXYZ>(option: T) {
        myFunctionThatTakesMyGeneric(option.value)
    }

    return (
        <>
            <myElement onChange={onChangeHandler}>
                Blah blah!
            </myElement>
        </>
    )

How can I modify the syntax so the above code is valid?

CodePudding user response:

You don't actually need to make the onChangeHandler generic.

import React from 'react'

interface MyInterfaceXYZ<T> {
    displayName: string
    value: T
}

interface MyComponentProps<T> {
    myFunctionThatTakesMyGeneric: (value: T) => void
    options: MyInterfaceXYZ<T>[]
}
// The syntax on the line below is totally invalid
function InputSelect<T>({
    myFunctionThatTakesMyGeneric,
    options,
} : MyComponentProps<T>) {

    // `<T extends MyInterfaceXYZ>` requires 1 argument 
    // that I don't know how to pass here
    const onChangeHandler  = (option: MyInterfaceXYZ<T>) => {
        myFunctionThatTakesMyGeneric(option.value)
    }

    return (
        <>
            <div onChange={() => onChangeHandler(options[0])}>
                Blah blah!
            </div>
        </>
    )
}

<>
  <InputSelect myFunctionThatTakesMyGeneric={(a:string) => {console.log(a);}} options={[{displayName: 'string', value:'1'}]}  />
  <InputSelect myFunctionThatTakesMyGeneric={(a:number) => {console.log(a);}} options={[{displayName: 'number', value:1}]}  />
</>

Playground link

Also I changed the onChange to onChange={() => onChangeHandler(options[0])}, because you need to pass an option to the function. options[0] is probably not what you want.

  • Related