0

I want to switch between components depending on passed prop. If type === 'check' - render CheckList, otherwise render RadioList. Both of these components accept same props. I tried following example given [here][1]. But when I tried running the code, I got error:

Element type is invalid: expected a string (for built-in components) 
or a class/function (for composite components) but got: undefined. 
You likely forgot to export your component from the file it's defined in, 
or you might have mixed up default and named imports.
    
Check the render method of `List`.

My code in List.tsx is:

import CheckList from './Check/CheckList';
import RadioList from './Radio/RadioList';
import Props from './typings';

const list = {
  check: CheckList,
  radio: RadioList,
};

const List = ({type = 'radio', selected, options, callback}: Props) => {
  const ListType = list[type];

  return (
    <ListType list={options} selected={selected} callback={callback} />
  );
};

export default List;

When in return I replace ListType with either RadioList or CheckList - it works. I don't understand why it breaks when I use ListType. I checked all imports/exports and the fact that components work fine outside of List shows that they are not the problem.

I actually call for List inside RadioList component, so that it can return either radio list or check list for children:

import React from 'react';
import RadioButton from '../../../atoms/RadioButton/RadioButton';
import Props from './typings';
import {StyledSubcategory} from './styles';
import List from '../List';

const RadioList = ({list, selected, group, callback}: Props) => {
  return (
    <>
      {list.map((option, key) => (
        <>
          <RadioButton
            key={key}
            checked={false}
            label={option.label}
            value={option.value}
            callback={callback}
          />

          {option.sublist && (
            <StyledSubcategory $visible={true}>
              <List
                type={option.sublist.type}
                selected={false}
                options={option.sublist.options}
                callback={callback}
              />
            </StyledSubcategory>
          )}
        </>
      ))}
    </>
  );
};

export default RadioList;

My props for list are:

const list = {
  type: 'radio',
  options: [
    {
      label: 'all',
      value: 'all',
    },
    {
      label: 'painting',
      value: 'painting',
      sublist: {
        type: 'radio',
        options: [
          {label: 'all', value: 'all'},
          {label: 'acrylic', value: 'type-acrylic'},
          {label: 'oil', value: 'type-oil'},
          {label: 'watercolour', value: 'type-watercolour'},
        ],
      },
    },
  ],
};

UPDATE: I found what the issue was. My list object with my components was declared outside of my List, however once I brought it inside it worked:

import CheckList from './Check/CheckList';
import RadioList from './Radio/RadioList';
import Props from './typings';

const List = ({type = 'radio', selected, options, callback}: Props) => {
  const list = {
    check: CheckList,
    radio: RadioList,
  };
  const ListType = list[type];

  return (
    <ListType list={options} selected={selected} callback={callback} />
  );
};

Can someone explain why it's the case? export default List; [1]: https://stackoverflow.com/a/40896168/3629015

Alyona
  • 1,682
  • 2
  • 21
  • 44
  • Can you try to wrap your component with `div` or `Fragment` and then return. It will work. In your case when it renders first time its returning nothing. – Qubaish Bhatti Jun 01 '22 at 09:36
  • Just make sure you are exporting checklist and radiolist as a default export. Check code-sandbox its working for me. https://codesandbox.io/s/stupefied-darkness-m2lk99?file=/src/App.js – Qubaish Bhatti Jun 01 '22 at 09:51
  • I tried using both `
    ` and `React.Fragment`. Didn't work. I checked again all exports, they are in place.
    – Alyona Jun 01 '22 at 09:59
  • Can you share `CheckList` or `RadioList` component. ? – Qubaish Bhatti Jun 01 '22 at 10:04
  • Can you show us where do you use and pass props to the List component? – Ozan Yurtsever Jun 01 '22 at 10:12
  • Qubaish Bhatti, CheckList isn't done yet - it accepts same props, but returns `
    ` at the moment.
    – Alyona Jun 01 '22 at 10:37
  • If I use `switch` statement to switch between `type`s to return either `RadioList` or `CheckList` it works fine. But I really like how clean code is and I want to understand why it's not working. – Alyona Jun 01 '22 at 12:05

1 Answers1

0

The problem is with the type property of the List component. You are passing option.sublist.options value to it, which is most probably undefined, and it overrides the default value radio as well.

Please make sure the value is not undefined, or pass it like so;

<List
   type={option?.sublist?.type ?? 'radio'}
   selected={false}
   options={option.sublist.options}
   callback={callback}
/>
Ozan Yurtsever
  • 1,274
  • 8
  • 32
  • But in List component I have a default value specified as `type = 'radio'`, so in case if it will be passed as `undefined`, it will change to `'radio'` – Alyona Jun 01 '22 at 10:44