React - Map dynamic component name within map loop - reactjs

I'm new to react and trying to create a menu bar of sorts. All the similar questions seem to be older or not quite what I need. Regardless, I can't get this to work so please help figuring this out.
I'm using react-icons and would like to dynamically name the component so I can use the icons within this loop but <{val.icon} /> is throwing an error: "'...' expected." What can I do to make this work? I also can't seem to declare variables in a return statement to work around this, or at least I can't figure out how to do so. Any idea?
const values = [
{ id: 1, text: "Home", icon: "MdHomeFilled" },
{ id: 2, text: "Schedule", icon: "MdEditCalendar" },
{ id: 3, text: "Scores", icon: "MdSportsTennis" },
{ id: 4, text: "Stats", icon: "IoIosStats" }
];
return (
<>
<ul>
{values.map((val) => (
<li onClick={() => setActiveId(val.id)}>
<div className={activeId === val.id ? "NavLinkBox selected":"NavLinkBox"}>
<div className="navLinkBoxHdr"><{val.icon} /></div>
<div className="navLinkBoxCnt">{val.text}</div>
</div>
</li>
))}
</ul>

You can't just use a component name (i.e. as a string) in order to render a component.
In order to render it, you need to import it like you would regularly, then convert it into a variable with a capitalized name. For example:
import MdHomeFilled from './MdHomeFilled';
import MdEditCalendar from './MdEditCalendar';
export default function App() {
const values = [
{ id: 1, text: "Home", icon: MdHomeFilled },
{ id: 2, text: "Schedule", icon: MdEditCalendar }
];
return (
<ul>
{values.map((val) => {
const IconComponent = val.icon; // This way you can use this field as a component
return (
<li key={val.id} onClick={() => setActiveId(val.id)}>
<div className={activeId === val.id ? "NavLinkBox selected":"NavLinkBox"}>
<div className="navLinkBoxHdr"><IconComponent /></div>
<div className="navLinkBoxCnt">{val.text}</div>
</div>
</li>
);
})}
</ul>
);
}

Related

Typescript React

I want to make a simple lists with items, but doesn't work and I dont know why. If I add "manually" these items, works. Sry for my english.
import './App.css'
const App = () => {
return (
<div className="App">
<ul>
{items.map((item, index) => {
<li key={index}><span>{item.title}</span></li>
})}
</ul>
</div>
);
}
export default App;
const items = [
{
title: "asd0",
image: ""
},
{
title: "asd1",
image: ""
},
{
title: "asd2",
image: ""
}
]
Someone could help me?
If you want to use TypeScript, you need to use something called interfaces and be specific about types with your data.
https://www.typescriptlang.org/docs/handbook/interfaces.html
To be able to render items, the array needs to be moved to inside the component. Here is index.js:
import './App.css'
const App = () => {
const items = [
{
title: "asd0",
image: ""
},
{
title: "asd1",
image: ""
},
{
title: "asd2",
image: ""
}
]
return (
<div className="App">
<ul>
{items.map((item, index) => {
<li key={index}><span>{item.title}</span></li>
})}
</ul>
</div>
);
}
export default App;

Type 'IconType' is not assignable to type 'ReactNode'

have been looking for a way to properly render an icon in my component but ended up with an error from the title.
Profile.tsx:
<ul>
{socialLinks.map((socialLink) => (
<li key={socialLink.href}>
<a href={socialLink.href}>{socialLink.icon}</a>
</li>
))}
</ul>
data.ts
import { FaDiscord, FaGithub, FaTwitter } from "react-icons/fa";
export const socialLinks = [
{
name: "github",
href: "#",
icon: FaGithub,
},
{
name: "twitter",
href: "#",
icon: FaTwitter,
},
{
name: "discord",
href: "#",
icon: FaDiscord,
},
];
is there a way to fix this?
The icon is a functional component. You have to invoke it.
Either, invoke it directly in the data config:
{ icon: <FaGithub />, name: ..., href: ... }
or when mapping:
{socialLinks.map((socialLink) => {
const Icon = socialLink.icon;
return (
<li key={socialLink.href}>
<a href={socialLink.href}>
<Icon />
</a>
</li>
);
))}
You should be able to reassign the socialLinks.icon to a new variable and then render it as a React component in the tsx file. I believe the following should work:
<ul>
{socialLinks.map((socialLink) => {
const Icon = socialLink.icon
return (
<li key={socialLink.href}>
<a href={socialLink.href}><Icon/></a>
</li>
))}}
</ul>

Mapping links to components

I'm learning to react and wanted to create a card that, when clicked, routes the user to an external web page. I haven't seen any tutorials or explanations on this all I keep finding is for internal website navigation. I tried doing this in different ways but can't find the correct way to do this.
my component:
import React from "react";
function Card (props) {
const handleClick = () => {
return
}
return (
<div>
}
<div className="link-container" onClick= {()=> {
return handleClick();}
}>
<div className="row">
<div className="card">
<hr className="divide"></hr>
<img className="img" src={props.img} alt="social-icon" />
<h4 className="name">{props.name}</h4>
</div>
</div>
</div>
</div>
)
}
export default Card;
href links to be used:
const links = [
{
id: 1,
name: "Youtube",
img:"./img/youtube1.svg",
href: "https://www.youtube.com/c/SubwaySounds"
},
{
id: 2,
name: "Spotify",
img:"./img/spotify.svg",
href: "https://artists.spotify.com/c/artist/3DM32kjsG7Pp5EM7o3Uv7t/profile/overview"
},
{
id: 3,
name: "Tiktok",
img:"./img/tiktok.svg",
href: "https://www.tiktok.com/#nysubwaysounds"
},
{
id: 4,
name: "Instagram",
img:"./img/Instagram1.svg",
href: "https://www.instagram.com/nycsubwaysounds/?hl=en"
},
{
id: 5,
name: "Shop",
img:"./img/shop.svg",
href: "https://my-store-11524143.creator-spring.com/"
}
]
export default links;
What you need to do is to create an element for each item for the list. For this, you can use the builtin JS map function.
For example, you can create a new variable holding the elements:
const linksElements = links.map(item => (<Card item={item} />));
and use it with {linksElements} inside of the return value.
I've created this as an example using your list: https://stackblitz.com/edit/react-yt1hfl?file=src/App.js. Note that this is a quick and dirty implementation, without any other components.

React - one state for managing 'active' flag on multiple compontents

I have a list of compontents I want to share the same state.
I want, at any given time, only the last selected component to have the active state whilst the others to be 'inactive'.
codesandbox link
Thanks.
EDIT:
for SO future proofing of potential dead links:
SidebarList Compontent:
const [active, setActive] = useState(false);
const handleActive = (i) => {
console.log(i);
i.currentTarget.className = active ? "a" : "b";
console.log(i.currentTarget.className);
};
const list = props.items.map((item) => {
return (
<ListItem key={item.id} handleActive={(item) => handleActive(item)}>
{item.text}{" "}
</ListItem>
);
});
return (
<div className="sidebar__list">
<h2>{props.title}</h2>
<ul>{list}</ul>
</div>
);
}
ListItem compontent
function List_item(props) {
return (
<li onClick={props.handleActive}>
<a>
<h2>{props.children}</h2>
</a>
</li>
);
}
export default List_item;
And the App component:
export default function App() {
return (
<div className="App">
<SidebarList
title="About"
items={[
{ id: 1, text: "Item 1 arr" },
{ id: 2, text: "Item 2 arr" }
]}
/>
<SidebarList
title="Templates"
items={[
{ id: 1, text: "Item 1 arr" },
{ id: 2, text: "Item 2 arr" }
]}
/>
</div>
);
}
TLDR; react router v4 NavLink perform singular maintenance of one active className, dependant on the current routed page.
NavLink property 'activeClassName' will parse a specfied className to the current routed page, whilst removing on non-routed pages. All state management in this question is therefore redundant.

How to pass multiple arguments through React Context (from Consumer to Provider)?

I am creating a simple app using create-react-app
And was exploring using React Context API to pass few stuff from one component to another component.
Spice.js
const spiceList = [
{
id: 1,
title: 'Spice 11',
name: require('./images/spice1.jpeg')
},
{
id: 2,
title: 'Spice 22',
name: require('./images/spice2.jpeg')
}
];
return (
<div>
<h1>Welcome to Spices</h1>
<SpiceContext.Provider value={'Masala'} imgSrc={img3}>
<SpiceList/>
</SpiceContext.Provider>
</div>
</div>
);
}
}
export default Spice;
Consumer in SpiceList Where I plan to retrieve multiple attributes instead of a single value attribute.
How this could be achieved? Thanks
<>
<h1>{props.title}</h1>
<SpiceContext.Consumer>
{spiceContext=> <img src={spiceContext.value} alt={spiceContext.title}/>
}
</SpiceContext.Consumer>
</>
SpiceContext
import React from 'react';
const SpiceContext = React.createContext(null);
export default SpiceContext;
First create your object to share.
const myOptions = [
{
key: 1,
title: 'Title',
other: 'other',
},
{
key: 2,
title: 'Title',
other: 'other',
}
];
Then pass it down.
return (
<div>
<h1>Welcome to Spices</h1>
<SpiceContext.Provider value={myOptions} imgSrc={img3}>
<SpiceList/>
</SpiceContext.Provider>
</div>
</div>
);
Then you will receive those in the same way:
<h1>{props.title}</h1>
<SpiceContext.Consumer>
{(options) => (
<>
{options.map((option) => (
<img key={option.key} src={option.other} alt={option.title}/>
))}
</>
)}
</SpiceContext.Consumer>

Resources