Lalablala
Lalablala

Reputation: 77

Dynamically access object with react components in typescript by key

I want to dynamically select a react component from a object with a key

import React, {useState, useEffect} from 'react'
import ComponentA from '@components/ComponentA';
import ComponentB from '@components/ComponentB';
  
const DynamicComponent: React.FC = ({key}) => {  
  const [Component, setComponent] = useState<any>();
  const COMPONENTS = {
    COMPONENT_A: ComponentA,
    COMPONENT_B: ComponentB,
  };

  useEffect(() => {
    if (key) setComponent(COMPONENTS[key])
  }, [key]);

  return Component ? React.createElement(Component) : null;
};

With this i get a type error on COMPONENTS[key]

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ COMPONENT_A: FC<{}>; }'.
No index signature with a parameter of type 'string' was found on type '{ COMPONENT_A: FC<{}>; }'.

How do i type this correctly?

Upvotes: 2

Views: 1051

Answers (3)

Lalablala
Lalablala

Reputation: 77

I found the answer here: https://stackoverflow.com/a/55014391

Typing the COMPONENTS object fixed my problem.

import React, {useState, useEffect} from 'react'
import ComponentA from '@components/ComponentA';
import ComponentB from '@components/ComponentB';
  
const DynamicComponent: React.FC = ({key}) => {  
  const [Component, setComponent] = useState<any>();
  const COMPONENTS: {[key: string]: React.FC<any>} = {
    COMPONENT_A: ComponentA,
    COMPONENT_B: ComponentB,
  };

  useEffect(() => {
    if (key) setComponent(COMPONENTS[key])
  }, [key]);

  return Component ? React.createElement(Component) : null;
};

Upvotes: 1

Giorgi Andriadze
Giorgi Andriadze

Reputation: 306

You're missing default value for useState

You can use null as default value:

useState(null)

Like this:

 const [Component, setComponent] = useState<any>(null);

Upvotes: 1

Long Nguyen Duc
Long Nguyen Duc

Reputation: 1325

You need define PropTypes for your component, also type of Key.

import React, {useState, useEffect} from 'react'
import ComponentA from '@components/ComponentA';
import ComponentB from '@components/ComponentB';

type Key = "COMPONENT_A" | "COMPONENT_B"

type Props = { key: Key }
  
const DynamicComponent: React.FC<Props> = ({key}) => {  
  const [Component, setComponent] = useState<any>();
  const COMPONENTS = {
    COMPONENT_A: ComponentA,
    COMPONENT_B: ComponentB,
  };

  useEffect(() => {
    if (key) setComponent(COMPONENTS[key])
  }, [key]);

  return Component ? React.createElement(Component) : null;
};

Upvotes: 1

Related Questions