Home > front end >  How do I pass a variable as a react component while bypassing conditional render?
How do I pass a variable as a react component while bypassing conditional render?

Time:02-03

import { ReactComponent as GreenIcon } from '../assets/green.svg'
import { ReactComponent as YellowIcon } from '../assets/yellow.svg'
import { ReactComponent as RedIcon } from '../assets/red.svg'

const GreenIconMemoized = memo(GreenIcon)
const YellowIconMemoized = memo(YellowIcon)
const RedIconMemoized = memo(RedIcon)

const STATUSES = ['ready', 'delay', 'stop']
const icons = new Map([
  ['ready', GreenIconMemoized],
  ['delay', YellowIconMemoized],
  ['stop', RedIconMemoized]
])

const [sampleStatus, setSampleStatu] = useObserver(() => [
  sampleSTORE.sampleStatus,
  sampleSTORE.setSampleStatus
])

const sampleArray: ComponentType[] = useMemo(() => {
  return STATUSES.map((status: string) => {
    const Icon = icons.get(status)
    return {
      id: status,
      label: status,
      isSelected: status === sampleStatus,
      onSelect: (): void => {
        setSampleStatus(status)
      },
      leftComponent: Icon ? <Icon /> : undefined
    }
  })
}, [sampleStatus])

In the code above, what is the best way to pass the Icon value as a react component without the need of a conditional render? Both STATUSES and icons are hard coded into the system, and therefore are not really variable - the else condition will never be reached. But if I attempt to pass for example:

...
   leftComponent: <Icon />
...

I am given the error "JSX element type 'Icon' does not have any construct or call signatures."

CodePudding user response:

I would recommend using an object instead of a Map. That way, typescript can know exactly which keys are valid, and thus knows that undefined is impossible (as long as you provide a valid key).

const STATUSES = ['ready', 'delay', 'stop'] as const;
const icons = {
  ready: GreenIconMemoized,
  delay: YellowIconMemoized,
  stop: RedIconMemoized
}

//...
return STATUSES.map((status) => {
  const Icon = icons[status];
  // ...
    leftComponent: <Icon />
  // ...

Note that i used as const on the STATUSES. This causes typescript to infer the type to be readonly ["ready", "delay", "stop"], not string[]. That means that later, when you map over the array, status is of type "ready" | "delay" | "stop", not string, and therefore you've proven to typescript that you'll only access valid keys.

If you prefer, you could do the types more explicitly, as in:

const STATUSES: ("ready" | "delay" | "stop")[] = ['ready', 'delay', 'stop'];
// ...
return STATUSES.map((status: "ready" | "delay" | "stop") => {

// OR:
const STATUSES: (keyof typeof icons)[] = ['ready', 'delay', 'stop'];
// ...
return STATUSES.map((status: keyof typeof icons) => {
  •  Tags:  
  • Related