简体   繁体   中英

Why is my React component icon coming out as a typeof object?

I'm trying to create a custom icon set defined from a css stylesheet but it throws the error " Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: <myIcon /> . Did you accidentally export a JSX literal instead of a component? " I don't know why.

In myIcon.jsx, I've created a component myIcon that renders the custom icon in jsx form. myIconsMap creates an object map, where each key is the name of the icon and its value is a React component (made from myIcon ).

//myIcon.jsx

import React from 'react';
import 'styles/fonts/customIcons.css';

const myIcons = ['randomIcon1', 'randomIcon2'];

const myIcon = props => {
  return <div className={`icon-${props.name}`} />;
};

const myIconsMap = myIcons.reduce((icons, iconName) => {
  icons[iconName] = <myIcon name={iconName} />;
  return icons;
}, {});

const randomIcon1 = myIconsMap.randomIcon1;
const randomIcon2 = myIconsMap.randomIcon2;

export {randomIcon1, randomIcon2};

But randomIcon1 and randomIcon2 both return typeof object, and I'm confused why because they both reference a React component (ie `). I think this is the problem; I need it to be a typeof function instead of object somehow before the browser can render it correctly.

After, I export my icons from myIcon.jsx to allIcons.jsx. This file is what renders the icons on the browser:

//allIcons.jsx

import {randomIcon1, randomIcon2} from './myIcon';

export const icons = {
  randomIcon1,
  randomIcon2  
}

const Icon = (name) => {
  const IconComponent =
    icons[`${name.substring(0, 1).toUpperCase()}${name.substring(1)}`];

  return <IconComponent />;
};

Anyone have any idea why this is happening?

icons[iconName] = <myIcon name={iconName} />;

This line doesn't create a new component. It renders the existing component, producing a react element. That element is a description of what to put on the page, which looks something like this:

{
  $$typeof: Symbol(react.element),
  type: MyIcon,
  key: null,
  ref: null,
  props: { name: iconName }
}

It is possible to use this to put stuff on the page, but not with a JSX tag like <IconComponent /> . That would try to render it again, which can't happen since it has already been rendered. To use this element, you'd have to do:

const Icon = (name) => {
  const iconElement =
    icons[`${name.substring(0, 1).toUpperCase()}${name.substring(1)}`];

  return iconElement;
}

The other approach (and the one i'd recommend) is to create separate components for each icon. To do that, you just need to wrap your existing code in a function, thus turning it into a component.

icons[iconName] = () => <myIcon name={iconName} />;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM