How to conditionally display a material-ui breadcrumb within a component - reactjs

I'm using mui breadcrumbs within my react app and unsure why I am not seeing the second separator as part of my <MyBreadcrumb /> component.
I am also trying to conditionally display my breadcrumb list but I think now that this could be the issue as it's also placing each breadcrumb item on separate lines.
The main contents looks as follows:
import * as React from 'react';
import Typography from '#mui/material/Typography';
import Breadcrumbs from '#mui/material/Breadcrumbs';
import { Link, useParams } from "react-router-dom";
export default function MyBreadcrumb() {
const { instrument, name } = useParams();
return (
<Breadcrumbs aria-label="breadcrumb">
<Link to={"/"}>
Home
</Link>
{ !instrument ? (
<Typography color="text.primary">{name}</Typography>
) : (
<>
<Link to={-1}>
Musician
</Link>
<Typography color="text.primary">{name} - {instrument}</Typography>
</>
)}
</Breadcrumbs>
)
}
Basically if instrument is undefined then I expect to see the following breadcrumb menu:
Home / Tom
Otherwise if instrument has a value, I then expect to see the following breadcrumb menu:
Home / Musician / Bob - guitar
I believe the issue with the second separator not appearing is because I'm not sure how to conditionally display my breadcrumb menu based on the above rules.

After checking the DOM element, I found something interesting. I have a quick fix for this, but not the best answer I think.
codesandbox: https://codesandbox.io/s/mui-5-forked-fn21v1
import * as React from "react";
import Typography from "#mui/material/Typography";
import Breadcrumbs from "#mui/material/Breadcrumbs";
import { Link } from "react-router-dom";
export default function App() {
const instrument = true ? "guitar" : undefined;
const name = "Tom";
return (
<>
<Breadcrumbs aria-label="breadcrumb">
<Link to={"/"}>Home</Link>
{!instrument && <Typography color="text.primary">{name}</Typography>}
{/* OLD */}
{/* {instrument && (
<>
<Link to={-1}>Musician</Link>
<Typography color="text.primary">
{name} - {instrument}
</Typography>
</>
)} */}
{/* NEW */}
{instrument && <Link to={-1}>Musician</Link>}
{instrument && (
<Typography color="text.primary">
{name} - {instrument}
</Typography>
)}
</Breadcrumbs>
</>
);
}
So the quick fix is to seperate the Musician and {name} - {instrument} element to a different conditional rendering.
DOM screenshot with OLD code:
DOM screenshot with NEW code:
As you can see on OLD code, when we wrap the 2 elements with <>...</>, MUI will convert it into 1 list instead of 2, and meanwhile on the NEW code that we seperate the conditional rendering, MUI generate 2 lists.
I don't know what happen under the hood with MUI, but hope this little quick fix can help.

Related

React warning Maximum update depth exceeded: firebase-react-hook

Currently, I'm trying to check if the user is logged in for my home page and display some different components depending on the log-in status.
However, i'm getting this warning :
“Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.”
The following is my code in Appshell.js
import React from "react";
import TopRight from "./TopRight";
import { AppBar, Toolbar } from "#material-ui/core";
import BootstrapButton from "./BootstrapButton";
import { Link } from "react-router-dom";
import { useDocumentData } from "react-firebase-hooks/firestore";
import { useAuthState } from "react-firebase-hooks/auth";
import firebase from "firebase/app";
import SignOut from "./SignOut";
const firestore = firebase.firestore();
function AppShell() {
###The following line of code is causing the error###
const [currentUser] = useAuthState(firebase.auth());
#####################################################
const userRef = firestore.collection("Users").doc(currentUser?.uid);
const [user] = useDocumentData(userRef);
return (
<>
<div className="flex justify-between">
{currentUser ? <SignOut /> : <TopRight />}
</div>
<AppBar elevation={0} position="static" style={{ background: "#EDEDED" }}>
<Toolbar>
<Link to="/">
<BootstrapButton color="default">Home</BootstrapButton>
</Link>
<Link to="/opportunities">
<BootstrapButton color="default">Opportunities</BootstrapButton>
</Link>
{user?.Class === "recruiter" ? (
<Link to="/myposts">
<BootstrapButton color="default">My Posts</BootstrapButton>
</Link>
) : (
<Link to="/organisations">
<BootstrapButton color="default">Organisations</BootstrapButton>
</Link>
)}
<Link to="/about">
<BootstrapButton color="default">About</BootstrapButton>
</Link>
</Toolbar>
</AppBar>
</>
);
}
export default AppShell;
I have tried placing the line of code const [currentUser] = useAuthState(firebase.auth()); inside a useEffect hook to only update when page is rendered but apparently its not allowed. Hence, any suggestion to get rid of this error is much appreciated, thanks!

How to render react-icon depending on String from Database?

I am trying to create multiple boxes with information and every box has an Icon. Right now I have hard-coded this as following:
<Box p={10} borderRadius='lg' bg={colorMode === 'light' ? 'gray.300' : 'gray.700'}>
<Stack spacing={5}>
<Box mt={5}>
<IconContext.Provider value={{size: '10vh'}}>
<div>
<IoLogoJavascript/>
</div>
</IconContext.Provider>
</Box>
<Box><Heading>JS & TS</Heading></Box>
<Progress size="lg" value={75} hasStripe isAnimated/>
</Stack>
</Box>
Now, so that I can dynamically add more of these components, I want to implement a database.
It's easy for the most part, I just don't know how I can implement it with the react-icons components?
Should I use something else or would it be possible?
You can create a custom component but you will need to import them all.
Here an example with fa icons:
import React from "react";
import "./styles.css";
import * as Icons from "react-icons/fa";
/* Your icon name from database data can now be passed as prop */
const DynamicFaIcon = ({ name }) => {
const IconComponent = Icons[name];
if (!IconComponent) { // Return a default one
return <Icons.FaBeer />;
}
return <IconComponent />;
};
export default function App() {
return (
<div className="App">
<DynamicFaIcon name="FaAngellist" />
<DynamicFaIcon />
</div>
);
}
How do you import your icons ?
I would go the base64 way from DB to show it in frontend, cause i see no way to import them dynamically without building again React front...

Need to click twice to update the state in react hooks. toggle button

i need to click two times on the button to update the state.
i have two buttons. when i toggles between the buttons the text should change.
I found some questions related to this but did not worked for me.
please find Below code.
import React,{useState} from "react";
import { BrowserRouter as Router, NavLink } from "react-router-dom";
import './SectionConnect.css';
const SectionConnect = () => {
const [activeButton, setActiveButton] = useState("company");
function toggleButton() {
setActiveButton(activeButton==="company" ? "individual" : "company");
}
return (
<div className="connect-container">
<div className="connect-wrapper">
<h2>How it works</h2>
{activeButton==="company"?<p>
We help your employees maximise potential through a bespoke, science-backed wellbeing platform.
</p>:<p>
We connect you with the very best practitioners and most effective
methods to achieve optimal health.
</p>}
<div className="connect-btn">
<NavLink
to="/"
exact
activeClassName="active-btn"
className="disable-btn"
onClick={toggleButton}
>
For companies
</NavLink>
<NavLink
to="/forIndividuals"
exact
activeClassName="active-btn"
className="disable-btn"
onClick={toggleButton}
>
For individuals
</NavLink>
</div>
</div>
</div>
);
};
export default SectionConnect
Not able to understand where i am going wrong.
Thanks in advance!
on toggleButton call like this onClick={()=> toggleButton()}

Access the route in different way in next js

I have an application in nextjs. There i built the next route:
<Link
href="colors/[type]"
as={`colors/${type}`}
>
<a>click</a>
</Link>
This route redirect me on /colors/red, or colors/blue and so on, depending by the user. type here is a varible = dynamic element.
Also i have other link:
<Link href="colors">
<a>click to colors</a>
</Link>
This route should redirect me on /colors, but when i click i get error, because the first url colors/red is not equal with this type: colors. So i have to put something after colors to make things happen.
How to solve the issue? and how to make my first route to accept the last parameter as optional.?
The best way to do this is to use dynamic route (more). Start by creating a new page in your /colors folder named [[...type]].js that will catch either /colors or /colors/red. This setup will also catch route like /colors/red/blue.
You can retrieve the variable part of the url by using the next Router (see example below).
import React from 'react';
import Link from "next/link";
import {useRouter} from "next/router";
export default () => {
const router = useRouter()
const { type } = router.query;
return (
<div>
<Link href={'/'}>
Home
</Link>
<Link href={'/colors/red'}>
Red
</Link>
<Link href={'/colors/blue'}>
Blue
</Link>
<div>
{type ? (
`Type: ${type}`
) : (
'no type'
)}
</div>
</div>
);
}

Can't include React UI frameworks (Grommet)

I have problems importing UI libraries, I had problem with ant design library so I decided to try different one, now I have problem importing Grommet.
What am I doing wrong? I added dependencies according documentation and added examples included in documentation yet still not working.
I am trying to execute this code from documentation
But it doesn't look the same at all
I work with codesandbox.io, here is link for the code on it
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
import Heading from "grommet/components/Heading";
import Box from "grommet/components/Box";
import Header from "grommet/components/Header";
import Title from "grommet/components/Title";
import Search from "grommet/components/Search";
import Menu from "grommet/components/Menu";
import Anchor from "grommet/components/Anchor";
import "grommet-css";
class HelloWorldApp extends React.Component {
render() {
return (
<div>
<Header>
<Title>Sample Title</Title>
<Box flex={true} justify="end" direction="row" responsive={false}>
<Search
inline={true}
fill={true}
size="medium"
placeHolder="Search"
dropAlign={{right: "right"}}
/>
<Menu dropAlign={{right: "right"}}>
<Anchor href="#" className="active">
First
</Anchor>
<Anchor href="#">Second</Anchor>
<Anchor href="#">Third</Anchor>
</Menu>
</Box>
</Header>
<Box>
<Heading>
Hello, I'm a Grommet Component styled with
grommet-css
</Heading>
</Box>
</div>
);
}
}
var element = document.getElementById("root");
ReactDOM.render(<HelloWorldApp />, element);
So according to your code:
<Menu dropAlign={{right: "right"}}>
was missing the icon attribute, without which the Menu component directly renders the Anchor, the menu-items component.
add import for the icon of your choosing, i.e: Actions ( from the example )
import Actions from 'grommet/components/icons/base/Actions';
add the icon attribute to the Menu component:
<Menu
icon={<Actions />}
dropAlign={{ right: 'right' }}
>
<Anchor href="#" className="active">First</Anchor>
<Anchor href="#">Second</Anchor>
<Anchor href="#">Third</Anchor>
</Menu>
here's a codesandbox.io link which fixes your issue:
https://codesandbox.io/s/237xo7y48p

Resources