How to use const in ReactJS - javascript

I have an array that I need to use twice and I don't want to repeat it in my code
const menuItems = [
{ route : 'home', text : 'Game Info' },
{ route : 'players-info', text : 'Players Info' },
{ route : 'money', text : 'Money' },
{ route : 'refunds', text : 'Refounds' },
{ route : 'videos', text : 'Videos' },
{ route : 'tips', text : 'Tips' }
];
and in the class I am doing
render () {
return <LeftNav
menuItems={menuItems} />
}
so, lets say that in another file, I want to use that same const menuItems, and render it like this
render () {
let tabs = menuItems.map((item) => {
return <Tab
key={item.route}
label={item.text}
route={item.route}
onActive={this._onActive} />
});
return <Tabs
initialSelectedIndex={0}>{tabs}
</Tabs>;
}
So, what should I do to use the const across different files?

// menuItems.js
export default const menuItems = [
{ route : 'home', text : 'Game Info' },
{ route : 'players-info', text : 'Players Info' },
{ route : 'money', text : 'Money' },
{ route : 'refunds', text : 'Refounds' },
{ route : 'videos', text : 'Videos' },
{ route : 'tips', text : 'Tips' }
];
// then you can import it like so
import menuItems from "./menuItems";

Related

Warning: <Element /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements

I'm trying to automatically create React Elements from strings corresponding to the react-icons library. But I am getting the following errors in the console:
Warning: <RiHeartPulseFill /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.
Warning: The tag <RiHeartPulseFill> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.
Currently I have a data file that consists of a name and iconName (see below)
const categoriesData = [
{
name: 'Vitals',
iconName: 'RiHeartPulseFill',
},
{
name: 'Body',
iconName: 'RiBodyScanFill',
},
{
name: 'Sleep',
iconName: 'RiHotelBedFill',
},
{
name: 'Metabolism',
iconName: 'RiLungsFill',
},
{
name: 'Stress',
iconName: 'RiMentalHealthFill',
},
{
name: 'Strength & Training',
iconName: 'RiRunFill',
},
{
name: 'Lifestyle',
iconName: 'RiCellphoneFill',
},
]
export default categoriesData
I want to dynamically render React elements with the exact name as the iconName in the above datafile as React-icons require specific elements with those names.
Then I try to create a list of navigation links (using the React Router <Link> syntax and adding a React-icon + Name. See the code below:
const menuCategories = categoriesData.map((category) => {
const IconElement = category.iconName
return (
<Link
to={`/data/${category.name.toLowerCase()}`}
key={category.name}
className="flex flex-row items-center gap-2"
>
<IconElement />
{category.name}
</Link>
)
})
The issue I run into is the following error: Warning: <RiHeartPulseFill /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.
I does not seems to be incorrect as it actually IS PascalCase. However when I check dev tools I see the following: <riheartpulsefill></riheartpulsefill>
I have no Idea why this happens. Any solutions?
Extra: Does anyone know how I can also import those icon names based on the initial data files. I'm thinking about creating an icon selection tool, so only the selected icons should be imported from the react-icons lib.
If you want to dynamically render these icon components then you'll typically need to import and specify them in the config instead of strings corresponding to their names.
Example:
import {
RiHeartPulseFill,
RiBodyScanFill,
RiHotelBedFill,
RiLungsFill,
RiMentalHealthFill,
RiRunFill,
RiCellphoneFill,
} from "react-icons/ri";
const categoriesData = [
{
name: 'Vitals',
iconName: RiHeartPulseFill,
},
{
name: 'Body',
iconName: RiBodyScanFill,
},
{
name: 'Sleep',
iconName: RiHotelBedFill,
},
{
name: 'Metabolism',
iconName: RiLungsFill,
},
{
name: 'Stress',
iconName: RiMentalHealthFill,
},
{
name: 'Strength & Training',
iconName: RiRunFill,
},
{
name: 'Lifestyle',
iconName: RiCellphoneFill,
},
];
export default categoriesData;
const menuCategories = categoriesData.map((category) => {
const IconElement = category.iconName;
return (
<Link
to={`/data/${category.name.toLowerCase()}`}
key={category.name}
className="flex flex-row items-center gap-2"
>
<IconElement />
{category.name}
</Link>
);
});
An alternative is to create and export a lookup object for the icon components.
import {
RiHeartPulseFill,
RiBodyScanFill,
RiHotelBedFill,
RiLungsFill,
RiMentalHealthFill,
RiRunFill,
RiCellphoneFill,
} from "react-icons/ri";
export const iconMap = {
RiHeartPulseFill,
RiBodyScanFill,
RiHotelBedFill,
RiLungsFill,
RiMentalHealthFill,
RiRunFill,
RiCellphoneFill,
};
const categoriesData = [
{
name: 'Vitals',
iconName: 'RiHeartPulseFill',
},
{
name: 'Body',
iconName: 'RiBodyScanFill',
},
{
name: 'Sleep',
iconName: 'RiHotelBedFill',
},
{
name: 'Metabolism',
iconName: 'RiLungsFill',
},
{
name: 'Stress',
iconName: 'RiMentalHealthFill',
},
{
name: 'Strength & Training',
iconName: 'RiRunFill',
},
{
name: 'Lifestyle',
iconName: 'RiCellphoneFill',
},
];
export default categoriesData;
const menuCategories = categoriesData.map((category) => {
const IconElement = iconMap[category.iconName];
return (
<Link
to={`/data/${category.name.toLowerCase()}`}
key={category.name}
className="flex flex-row items-center gap-2"
>
<IconElement />
{category.name}
</Link>
);
});
To allow for any react-icons/ri icon then in the UI component import all of react-icons/ri and conditionally render the icon component if it exists.
import { Link } from 'react-router-dom';
import * as ReactRiIcons from "react-icons/ri"; // <-- all RI icons
import * as ReactRxIcons from "react-icons/rx"; // <-- all RX icons
const ReactIcons = { // <-- all merged icons set
...ReactRiIcons,
...ReactRxIcons
};
...
const menuCategories = categoriesData.map((category) => {
const IconElement = ReactIcons[category.iconName];
return (
<Link
to={`/data/${category.name.toLowerCase()}`}
key={category.name}
className="flex flex-row items-center gap-2"
>
{IconElement && <IconElement />} // <-- handle possible undefined icon
{category.name}
</Link>
);
});
...
Use React.createElement. Take a look here to see how: Create react component dynamically
Heres my recursive example:
const demoData = [
{
tagName: 'MyButtonComponent',
children: [
{
tagName: 'MyChildComponent'
}
]
},
{
tagName: 'MyOtherComponent'
},
]
function recursivelyRenderChildren(elements) {
if(elements.length) {
return elements.map((element, index) => {
return React.createElement(elementData.tagName, {
key: element.fieldType+'-'+index,
children: recursivelyRenderChildren(element.children)
});
})
}
}
const arrayOfElements = recursivelyRenderChildren(demoData)

Mapping an array in my Next JS app not working

In my Next JS app I'm getting array and mapping them for the nav bar. but when i do it throws an error of TypeError: _utils_navigation__WEBPACK_IMPORTED_MODULE_6___default(...).map is not a function. my code is as follows.
{NavRoutes.map((navs, index) => {
console.log(navs.title);
console.log('bhsjvhjvs');
return (
<Link href={navs.link}>
<div className={`${
router.asPath === navs.link
? "text-active-red"
: ""
}`}>{navs.title}</div>
</Link>
)
})}
and the array
const NavRoutes = [
{
title: "HOME",
link: "/"
},
{
title: "NEWS",
link: "/news"
},
{
title: "CHANNEL",
link: "/channels"
},
{
title:"SHOWS",
link: "/shows"
},
{
title: "SCHEDULE",
link: "/schedules"
},
{
title: "CONTACT",
link: "/contact"
},
]
export default NavRoutes;
so how can i work through this?
check how you have imported it.
It should be like this
import NavRoutes from "../utils/navigations.js";
And apart from this, try to console NavRoutes and check you are getting expected value or not.

Map function is not working properly when I hit onClick

So I am making this project in ReactJs, which has a sidebar, where I am trying to implement dropdown menu.
Required Behavior
If I click in any of the option of the sidebar, if it has a submenu, it will show. And close upon again clicking.
Current Behavior
If I click any of the options, all the submenus are showing at once.
For example if I click publications option, it shows me all the options, such as featured publications, journal publications.
How do I fix that?
My sidebarItems array
const sidebarItems = [
{
title: "Publications",
url: "#",
subMenu: [
{
title: "Journal Publications",
url: "#",
},
{
title: "Featured Publications",
url: "#",
},
],
},
{
title: "Team Members",
url: "#",
subMenu: [
{
title: "Current Members",
url: "#",
},
{
title: "Lab Alumni",
url: "#",
},
],
},
{
title: "Projects",
url: "#",
subMenu: [
{
title: "Project 1",
url: "#",
},
{
title: "Project 2",
url: "#",
},
{
title: "Project 3",
url: "#",
},
],
},
{
title: "News",
url: "#",
},
{
title: "Contact Us",
url: "#",
},
];
export default sidebarItems;
The Sidebar Component
import { useState } from "react";
import { Box, Text } from "#chakra-ui/react";
import sidebarItems from "./sidebarItems";
export default function Sidebar() {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<Box>
{sidebarItems.map((items) => {
return (
<Box
width='200px'
height='40px'
textAlign='center'
cursor='pointer'
onClick={() => {
setIsOpen(!isOpen);
}}
>
<Text>{items.title}</Text>
{isOpen
? items.subMenu?.map((item) => {
return <Text>{item.title}</Text>;
})
: ""}
</Box>
);
})}
</Box>
</div>
);
}
You have to use an array state variable. Your single state variable isOpen is dictating all the subMenus here:
{isOpen
? items.subMenu?.map((item) => {
return <Text>{item.title}</Text>;
})
: ""}
You need to have an array state variable here, so each sidebar item has a corresponding boolean to dictate opening/closing of value.
const [isOpen, setIsOpen] = useState(Array(sidebarItems.length).fill(false));
Now you have to ensure that you are setting it correctly and manipulating the right array element.
onClick={() => {
let newIsOpen = [...isOpen];
newIsOpen[index] = !isOpen[index];
setIsOpen(newIsOpen);
}}
I hope this helps you reach your solution
This is happening because you are using wrong logic and you don't specify which submenu should be shown.
First, delete the current state and dont use it.
Then, you should define another state like:
const [selectedMenu, setSelectedMenu] = useState("");
then, define this function:
const handleClick = (title) => {
setSelectedMenu(title);
}
after that, once you click on Box, you should invoke function like this:
onClick={() => handleClick(item.title)}
consequently, you should write your logic like this:
<Text>{items.title}</Text>
{item.title === selectedMenu
? items.subMenu?.map((item) => {
return <Text>{item.title}</Text>;
})
: ""}
I think the problem is occurring because you have only 1 state variable set for every sidebar option. Every sidebar option should have its own variable keeping track of whether its submenu should open or not.
In your code, when the isOpen state variable is set to true then when the function maps over all the options the variable's value will always be true.
Try setting a variable for each of the menu options which contains whether the submenu should open or not.

React : Warning: Failed prop type: Cannot read property 'apply' of undefined

I am working on a navbar in react and i have been getting this error, and i have not found a working solution yet. Here is the piece of my code. I am trying to use react prop-types library to validate my navbar props with either a link or a dropdown. Below is the piece of code i have written.
NavBar.js
const NavBar = ({ navItems }) => {
return (
<nav role="navigation" className={styles.navBar}>
<Logo type="text">
ABCD
</Logo>
<div className={[styles.collapse, styles.noCollapse].join(' ')}>
<SearchBox />
<NavItems navItemsData={navItems} />
</div>
</nav>
);
};
NavItems.js
const NavItems = ({ navItemsData }) => {
return (
<ul className={styles.navItems}>
{navItemsData.map(navItemData => {
let navItem = <NavItem {...navItemData} key={navItemData.id} />
if (navItemData.type === 'dropdown') {
navItem = <NavDropDownItem {...navItemData} key={navItemData.id} />
}
return navItem;
})}
</ul>
);
};
PropTypes Checker(in same file as NavItems) :-
NavItems.propTypes = {
navItemsData: PropTypes.arrayOf(PropTypes.shape({
id : PropTypes.number,
type: PropTypes.oneOf(['link', 'dropdown']).isRequired,
linkText: requiredIf(PropTypes.string.isRequired, props => props.type === 'link'),
title : requiredIf(PropTypes.string.isRequired, props => props.type === 'dropdown'),
dropDownList: requiredIf(PropTypes.arrayOf(PropTypes.shape({ linkText: PropTypes.string.isRequired })), props => props.type === 'dropdown')
}))
};
I keep getting this warning in the console. As follows :-
Warning: Failed prop type: Cannot read property 'apply' of undefined
in NavItems (at NavBar.js:15)
in NavBar (at App.js:35)
in div (at App.js:34)
in App (at src/index.js:7)
The props i am passing :
const navItems = [{
id : 1,
type : 'link',
linkText : 'Link1'
},{
id : 2,
type : 'link',
linkText : 'Link2'
}, {
id : 3,
type : 'link',
linkText : 'Link3'
}, {
id : 4,
type : 'link',
linkText : 'Link4'
},{
id : 5,
type : 'link',
linkText : 'Link5'
},{
id : 6,
type : 'dropdown',
dropDownList : [{
linkText : 'LinkText'
}]
}]
Any help would be appreciated.
When you are using requiredIf, the first parameter should be the expected type. But it should not have the isRequired part. For example, your validation should be as follows.
NavItems.propTypes = {
navItemsData: PropTypes.arrayOf(PropTypes.shape({
id : PropTypes.number,
type: PropTypes.oneOf(['link', 'dropdown']).isRequired,
linkText: requiredIf(PropTypes.string, props => props.type === 'link'),
title : requiredIf(PropTypes.string, props => props.type === 'dropdown'),
dropDownList: requiredIf(PropTypes.arrayOf(PropTypes.shape({ linkText: PropTypes.string.isRequired })), props => props.type === 'dropdown')
}))};
There is no need to do PropTypes.string.isRequired inside requiredIf as it already covers the required case.
NavItems.propTypes = {
navItemsData: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number,
type: PropTypes.oneOf(["link", "dropdown"]).isRequired,
linkText: requiredIf(PropTypes.string, props => props.type === "link"),
title: requiredIf(PropTypes.string, props => props.type === "dropdown"),
dropDownList: requiredIf(
PropTypes.arrayOf(PropTypes.shape({ linkText: PropTypes.string })),
props => props.type === "dropdown"
)
})
)
};

Reactjs: How to update component when a new prop comes up?

I want to update/re-render the component after a new update comes up. All I am doing is:
I have a list of dealers for a casino game, what I want is to add a new dealer, and once the new dealer is added then display it in the view. It is actually happening, but in order for me to see the new dealer, I have to reload the page.
I am not updating the state, I am working with this.props. Look at my code
#connectToStores
export default class Dealers extends Component {
constructor (props) {
super(props);
this.state = {}
}
componentWillMount () {
GetDealersActions.getDealers();
}
static getStores () {
return [ GetDealersStore, CreateDealersStore ];
}
static getPropsFromStores () {
return {
...GetDealersStore.getState(),
...CreateDealersStore.getState(),
}
}
render () {
return (
<div>
{!!this.props.dealerData ?
this.props.dealerData.dealersData.map((dealer) => {
return (here I am rendering what I need);
: <p>Loading . . .</p>
</div>
}
_addDealer = () => {
CreateDealersActions.createDealer({
DealerName : this.refs.DealerName.getValue(),
CardId : this.refs.CardId.getValue(),
NickName : this.refs.NickName.getValue(),
});
}
}
as you see the component above in the code is doing the initial rendering properly, the problem comes up when you hit _addDealer(), which is not updating the component, you should reload the page in order to see the new item in the view.
If you do a console.log(this.props); within _addDealer(), you will get something like this
{params: Object, query: Object, dealerData: Object, newDealerData: null}
where dealerData holds the full data of the dealers in the view but you can't see there the new dealer created. And newDealerData remains null
so, what do you think I should do in order to update the component everytime a new prop/dealer comes up ? or how do I update the props? which is the proper method in this situation ?
here is the full code for stores and actions just in case
action
#createActions(flux)
class CreateDealersActions {
constructor () {
this.generateActions('createDealerSuccess', 'createDealerFail');
}
createDealer (data) {
const that = this;
that.dispatch();
axios.post(`${API_ENDPOINT}/create-dealer/create-dealer`, data)
.then(function success (data) {
that.actions.createDealerSuccess({data});
})
}
};
store
#createStore(flux)
class CreateDealersStore {
constructor () {
this.state = {
newDealerData : null,
};
}
#bind(CreateDealersActions.createDealerSuccess)
createDealerSuccess (data) {
this.setState({
newDealerData : data.response.config.data,
});
}
}
the Dealers component is within a tab named management, which is this one:
const menuItems = [
{ route : 'dealers', text : 'Dealers' },
{ route : 'game-info', text : 'Game Info' },
{ route : 'player-info', text : 'Players Info' },
{ route : 'money', text : 'Money' }
];
export default class Management extends React.Component {
static propTypes = {
getActivePage : React.PropTypes.func,
menuItems : React.PropTypes.arrayOf(React.PropTypes.object),
}
static contextTypes = {
router : React.PropTypes.func,
}
render () {
return (
<div>
<TabsMainMenu menuItems={menuItems} getActivePage={this._getActivePage} />
<RouteHandler />
</div>
);
}
_getActivePage = () => {
for (const i in menuItems) {
if (this.context.router.isActive(menuItems[i].route)) return parseInt(i, 10);
}
}
}

Categories

Resources