skip to Main Content

I have a list of components which accept props like this

export default function Item1({fontSize, color, ...props}) {
  return (
      <SvgIcon
        fontSize={fontSize}
        color={color}
        viewBox="0 0 18 18"
        alignmentBaseline="middle"
        {...props}
      >
          <somethingElse />
      </SvgIcon>
  )
}

I want to create a wrapper class such that it accepts name of the item and returns these items. I created something but I feel it’s not a good practise to write code like below:-

export default function WrapperComponent({name, fontSize, color, ...props }) {
  if(name === 'Item1'){
    return <Item1 fontSize={fontSize} color={color} />
  }
  if(name === 'Item2'){
    return <Item2 fontSize={fontSize} color={color} />
  }
  if(name === 'Item3'){
    return <Item3 fontSize={fontSize} color={color} />
  }
  return(
    <div>
      {children}
    </div>
  )
}

I thought of creating a mapping here but I’m not sure how I can achieve that?

4

Answers


  1. I find the switch statement useful for these situations. It returns something different depending on what your variable is. It also includes a default:

    export default function WrapperComponent({name, fontSize, color, ...props }) {
      switch (name) {
        case 'Item1':
          return <Item1 fontSize={fontSize} color={color} />;
        case 'Item2':
          return <Item2 fontSize={fontSize} color={color} />;
        case 'Item3':
          return <Item3 fontSize={fontSize} color={color} />;
        default:
          return <div>{children}</div>;
      }
    }
    
    Login or Signup to reply.
  2. If this mapping is to be bound to the WrapperComponent, you can create a finite state with a plain JS object:

    const items = {
     Item1: ({fontSize, color}) => <Item1 fontSize={fontSize} color={color} />
     Item2: ({fontSize, color}) => <Item2 fontSize={fontSize} color={color} />
    }
    
    export default function WrapperComponent({name, fontSize, color, ...props }) {
      const item = items[name];
    
      if(item) {
        return item({ fontSize, color });
      }
    
      return(
        <div>
          {children}
        </div>
      )
    }
    

    Here is an example in CodeSandbox:

    https://codesandbox.io/s/react-finite-state-with-plain-js-object-rh9ktx?file=/src/App.js

    Login or Signup to reply.
  3. Basically you need the name of the component to be dynamic. You can create an items.js file as follows:

    import Item1 from 'items/Item1';
    import Item2 from 'items/Item2';
    import Item3 from 'items/Item3';
    // and so on...
    
    const items = {
      item1: Item1,
      item2: Item2,
      item3: Item3,
      // and so on...
    }
    
    export const getItem = (name) => {
      return items[name];
    }
    

    In your wrapper, you can use the getItem function as follows:

    import { getItem } from 'items';
    
    export default function WrapperComponent({name, fontSize, color, ...props }) {
      const Item = getItem(name);
    
      if (Item) {
        return <Item fontSize={fontSize} color={color} />
      }
    
      return(
        <div>
          {children}
        </div>
      )
    }
    

    I use this method for loading components into a modal component dynamically, and this should work for your use case.

    I would also suggest in your case to make the <SomethingElse /> component dynamic instead of <ItemX />.

    Login or Signup to reply.
  4. i guess you want a map it for in the main entry file,you can have a clean code ,simple code and have a good sturcture,

    if so ,i advise you new a config file ,write a function to return the item component, import it in the main entry file ,like the fellowing:

    // config.ts
    export const ItemSvgRender =(props)=>{return ...};
    // main.tsx
    import {ItemSvgRender} from "./config.ts";
    
    // use it
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search