在 Gatsby 中如何从 gatsby-config 的 menuLinks 动态渲染 React 图标?
In Gatsby how to render React Icons dynamically from gatsby-config's menuLinks?
遵循 Gatsby 的 Creating Dynamic Navigation in Gatsby I created a barebones menu and wanted to see if I can add React Icons' 组件文档:
gatsby-config.js(精简)
menuLinks:[
{
name:'home',
icon: 'AiFillHome',
link:'/'
},
{
name:'contact',
icon: 'AiFillHome',
link:'/contact'
}
]
在我尝试创建外部 menuLinks
文件作为模块时发现 Gatsby 出错后,示例:
作为模块的方法失败:
import React from 'react'
// React Icons
import { AiFillHome } from 'react-icons/ai'
const Menu = [
{
name:'home',
icon: <AiFillHome />,
link:'/'
},
{
name:'contact',
icon: <AiFillHome />,
link:'/contact'
}
]
export default Menu
我的查询没有问题:
const data = useStaticQuery(
graphql`
query {
site {
siteMetadata {
menuLinks {
name
icon
link
}
}
}
}
`,
)
在一个文件中,我已将菜单道具从我的查询传递到然后映射。
(精简文件):
{menu.map((menuItem, key) => {
return (
<Link key={key} to={menuItem.link}>
<div>
<span className="icon">{`<${menuItem.icon} />`}</span>
{menuItem.name}
</div>
</Link>
)
})}
我的 icon
不呈现。我也试过:
<span className="icon" component={menuItem.icon} />
不起作用。我也试过:
<span className="icon"><menuItem.icon /></span>
和:
<span className="icon">{React.createElement(menuItem.icon)}</span>
研究:
- Making an HTML string from a React component in background, how to use the string by dangerouslySetInnerHTML in another React component
在 Gatsby 中,如何将图标的组件名称传递给 menuLinks
并稍后呈现它?
编辑
执行后:
{menu.map(({link, name, icon: Icon}) => {
return (
<Link key={name} to={link}>
<div>
<span className="icon"><Icon /></span>
{name}
</div>
</Link>
)
})}
浏览器不呈现 React 图标组件,在检查元素面板时我得到:
<span class="icon">
<aifillhome></aifillhome>
</span>
另请注意,我确实收到以下终端错误:
warning 'AiFillHome' is defined but never used no-unused-vars
这是预料之中的,但这让我想知道我该如何引入:
import { AiFillHome } from 'react-icons/ai'
尝试这样的事情:
{menu.map(({link, name, icon: Icon}) => {
return (
<Link key={name} to={link}>
<div>
<span className="icon"><Icon /></span>
{name}
</div>
</Link>
)
})}
由于您正在遍历 menu
元素,因此 icon
由于大写而未被解释为 React 元素。在上面的解构中,您将 icon
解析为 Icon
,因此将其呈现为 <Icon />
中的 React 组件应该可以解决问题,因为它是元素本身。
还有另一种解决方法似乎有点矫枉过正但会起作用:您始终可以使用 Map
来保存资产组件,例如:
const AssetComponentsTuple = new Map([
[`home`, <AiFillHome />],
[`otherAsset`, <AiFillHome2 />],
]);
export default AssetComponentsTuple;
您的菜单将变为:
const Menu = [
{
name:'home',
icon: 'home',
link:'/'
},
{
name:'contact',
icon: 'otherAsset',
link:'/contact'
}
]
然后在循环中:
{menu.map(({link, name, icon}) => {
let IconComponent = AssetComponentsTuple.get(icon);
return (
<Link key={name} to={link}>
<div>
<span className="icon"><IconComponent /></span>
{name}
</div>
</Link>
)
})}
你甚至可以去掉icon
属性,直接使用AssetComponentsTuple
中的name
,在这种情况下:AssetComponentsTuple.get(name)
实施:
const AssetComponentsTuple = new Map([
[`home`, <AiFillHome />],
[`otherAsset`, <AiFillHome2 />],
])
export default AssetComponentsTuple
会抛出以下错误:
Element type is invalid: expected a string (for built-in components)
or a class/function (for composite components) but got: object.
但该方法让我想到了以下解决方法:
{menu.map(({link, name, icon}) => {
return (
<Link key={name} to={link}>
<div>
<span className="icon"><IconRetrieve icon={icon} /></span>
{name}
</div>
</Link>
)
})}
这让我可以为组件传递图标字符串和三元组。
IconRetrieve
分量:
import React from 'react'
import PropTypes from 'prop-types'
// React Icons
import { AiFillHome } from 'react-icons/ai'
import { MdCall } from 'react-icons/md'
import { BiErrorCircle } from 'react-icons/bi'
const IconRetrieve = ({ icon }) => {
const mapIcons = new Map([
[`home`, <AiFillHome />],
[`contact`, <MdCall />],
[`default`, <BiErrorCircle />],
])
return mapIcons.has(icon) ? mapIcons.get(icon) : mapIcons.get('default')
}
IconRetrieve.propTypes = {
icon: PropTypes.string.isRequired,
}
export default IconRetrieve
这种方法的优点是我可以创建 SVG 组件或与此相关的任何组件,并且 return 它基于图标字符串。
遵循 Gatsby 的 Creating Dynamic Navigation in Gatsby I created a barebones menu and wanted to see if I can add React Icons' 组件文档:
gatsby-config.js(精简)
menuLinks:[
{
name:'home',
icon: 'AiFillHome',
link:'/'
},
{
name:'contact',
icon: 'AiFillHome',
link:'/contact'
}
]
在我尝试创建外部 menuLinks
文件作为模块时发现 Gatsby 出错后,示例:
作为模块的方法失败:
import React from 'react'
// React Icons
import { AiFillHome } from 'react-icons/ai'
const Menu = [
{
name:'home',
icon: <AiFillHome />,
link:'/'
},
{
name:'contact',
icon: <AiFillHome />,
link:'/contact'
}
]
export default Menu
我的查询没有问题:
const data = useStaticQuery(
graphql`
query {
site {
siteMetadata {
menuLinks {
name
icon
link
}
}
}
}
`,
)
在一个文件中,我已将菜单道具从我的查询传递到然后映射。
(精简文件):
{menu.map((menuItem, key) => {
return (
<Link key={key} to={menuItem.link}>
<div>
<span className="icon">{`<${menuItem.icon} />`}</span>
{menuItem.name}
</div>
</Link>
)
})}
我的 icon
不呈现。我也试过:
<span className="icon" component={menuItem.icon} />
不起作用。我也试过:
<span className="icon"><menuItem.icon /></span>
和:
<span className="icon">{React.createElement(menuItem.icon)}</span>
研究:
- Making an HTML string from a React component in background, how to use the string by dangerouslySetInnerHTML in another React component
在 Gatsby 中,如何将图标的组件名称传递给 menuLinks
并稍后呈现它?
编辑
{menu.map(({link, name, icon: Icon}) => {
return (
<Link key={name} to={link}>
<div>
<span className="icon"><Icon /></span>
{name}
</div>
</Link>
)
})}
浏览器不呈现 React 图标组件,在检查元素面板时我得到:
<span class="icon">
<aifillhome></aifillhome>
</span>
另请注意,我确实收到以下终端错误:
warning 'AiFillHome' is defined but never used no-unused-vars
这是预料之中的,但这让我想知道我该如何引入:
import { AiFillHome } from 'react-icons/ai'
尝试这样的事情:
{menu.map(({link, name, icon: Icon}) => {
return (
<Link key={name} to={link}>
<div>
<span className="icon"><Icon /></span>
{name}
</div>
</Link>
)
})}
由于您正在遍历 menu
元素,因此 icon
由于大写而未被解释为 React 元素。在上面的解构中,您将 icon
解析为 Icon
,因此将其呈现为 <Icon />
中的 React 组件应该可以解决问题,因为它是元素本身。
还有另一种解决方法似乎有点矫枉过正但会起作用:您始终可以使用 Map
来保存资产组件,例如:
const AssetComponentsTuple = new Map([
[`home`, <AiFillHome />],
[`otherAsset`, <AiFillHome2 />],
]);
export default AssetComponentsTuple;
您的菜单将变为:
const Menu = [
{
name:'home',
icon: 'home',
link:'/'
},
{
name:'contact',
icon: 'otherAsset',
link:'/contact'
}
]
然后在循环中:
{menu.map(({link, name, icon}) => {
let IconComponent = AssetComponentsTuple.get(icon);
return (
<Link key={name} to={link}>
<div>
<span className="icon"><IconComponent /></span>
{name}
</div>
</Link>
)
})}
你甚至可以去掉icon
属性,直接使用AssetComponentsTuple
中的name
,在这种情况下:AssetComponentsTuple.get(name)
实施:
const AssetComponentsTuple = new Map([
[`home`, <AiFillHome />],
[`otherAsset`, <AiFillHome2 />],
])
export default AssetComponentsTuple
会抛出以下错误:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
但该方法让我想到了以下解决方法:
{menu.map(({link, name, icon}) => {
return (
<Link key={name} to={link}>
<div>
<span className="icon"><IconRetrieve icon={icon} /></span>
{name}
</div>
</Link>
)
})}
这让我可以为组件传递图标字符串和三元组。
IconRetrieve
分量:
import React from 'react'
import PropTypes from 'prop-types'
// React Icons
import { AiFillHome } from 'react-icons/ai'
import { MdCall } from 'react-icons/md'
import { BiErrorCircle } from 'react-icons/bi'
const IconRetrieve = ({ icon }) => {
const mapIcons = new Map([
[`home`, <AiFillHome />],
[`contact`, <MdCall />],
[`default`, <BiErrorCircle />],
])
return mapIcons.has(icon) ? mapIcons.get(icon) : mapIcons.get('default')
}
IconRetrieve.propTypes = {
icon: PropTypes.string.isRequired,
}
export default IconRetrieve
这种方法的优点是我可以创建 SVG 组件或与此相关的任何组件,并且 return 它基于图标字符串。