Why is my navbar "inexistant" for my other components? - reactjs

I just created a react app. First thing first, I wanted to make a navbar for the left side that will be accessible on every page. So far so good, it's working well, my issue arrises when I started to create my first page: it keeps clipping under my navbar, and nothing I do gets it out of under the bar, this is driving me insane. Here's the current state of the code...
App.js
class App extends Component {
render() {
return(
<Router>
<SideNavBar />
<Switch>
<Route exact path={"/"} component={HomePage} />
</Switch>
</Router>
);
}
}
Navbar
class SideNavBar extends Component {
constructor(props) {
super(props);
this.state = {
currentPath: props.location.pathname,
};
}
onClick (path) {
this.setState({ currentPath: path });
}
render() {
const { currentPath } = this.state;
const navItems =
[
{
path: "/",
css: "fas fa-home"
}, {
path: "/user",
css: "fas fa-user"
},
];
return(
<StyledSideNavBar>
{
navItems.map((item, index) => {
return (
<NavItem
item={item}
active={item.path === currentPath}
onClick={this.onClick.bind(this)}
key={index}
/>
);
})
}
</StyledSideNavBar>
);
}
}
Styled Navbar
const StyledSideNavBar = styled.div`
display: flex;
flex-direction: column;
justify-content: flex-start;
position: fixed;
height: 100vh;
width: 5rem;
top: 0;
left: 0;
padding-top: 1.5rem;
background-color: #EEEEEE;
`;
Navitem
class NavItem extends Component {
render() {
const { item, active, onClick } = this.props;
return(
<StyledNavItem active={active}>
<Link to={item.path} className={item.icon} onClick={() => onClick(item.path)} />
</StyledNavItem>
);
}
}
Styled Navitem
const StyledNavItem = styled.div`
display: flex;
flex-direction: row;
justify-content: center;
margin-bottom: 1.5rem;
a {
font-size: 2.7em;
color: ${(props) => props.active ? "#8394F5" : "black"};
:hover {
opacity: 0.7;
text-decoration: none;
}
}
`;
HomePage
class HomePage extends Component {
render() {
return (
<StyledHomePage>
{"Hi {user}!hhhhhhhhhhhhhhhhhhhhhh"}
</StyledHomePage>
);
}
}
Styled HomePage
const StyledHomePage = styled.div`
display: "flex",
margin: "5rem 5rem 0 5rem"
`;

The problem arises when you give postion: fixed to your NavBar, instead you should create a fluid design and remove fixed position. Let me know if you need more help in it.

Related

Component content not imported when importing styled components

I am building a site using React and have decided to use Styled Components. I have a component that is styled with Styled Components and is receiving a prop from my homepage where I am using an instance of this component. I have the styling being pulled into the homepage, but it is not pulling in the content of the component. When if I just pull in the whole component it pulls in the content fine, but it doesn't allow me to pass the prop, but if I import the component styling it doesn't pull in the content of the component, but the prop passes properly. So I need some help with how to pull in the content and styling and get the prop to pass.
I am pretty new to Gatsby and Styled Components so thanks for any help.
My Component Code
import React from 'react'
import styled from "styled-components"
import { useStaticQuery, graphql } from 'gatsby'
export const WhyChooseSection = styled.section`
border-bottom: 1px solid var(--charcoal);
`
export const WhyChooseH2 = styled.h2`
display: ${(props) => props.displayH2};
text-align: center;
`
export const WhyChooseContent = styled.div`
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
width: 100%;
max-width: 1160px;
margin: 0 auto;
padding-top: 40px;
padding-bottom: 40px;
column-gap: 100px;
row-gap: 30px;
#media(min-width: 992px) {
justify-content: space-between;
column-gap: 0;
}
.why-icon {
width: 180px;
height: 145px;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20px;
p {
margin-bottom: 0;
font-size: 19px;
font-weight: var(--font-bold);
}
}
`
export function WhyChooseIcons() {
const data = useStaticQuery(graphql`
{
whyChooseIcons: allWp {
nodes {
acfOptionsOfficeSettings {
whyChooseInteriorDetails {
whyChooseIcons {
whyChooseIconGraphic {
altText
id
sourceUrl
}
whyChooseIconTitle
}
}
}
}
}
}
`)
return (
<>
{data.whyChooseIcons.nodes.map((node, index) => (
<WhyChooseSection key={index}>
<WhyChooseH2>Why Choose Interior Details?</WhyChooseH2>
<WhyChooseContent>
{node.acfOptionsOfficeSettings.whyChooseInteriorDetails.whyChooseIcons && node.acfOptionsOfficeSettings.whyChooseInteriorDetails.whyChooseIcons.map((item) => (
<div className='why-icon' key={item.whyChooseIconGraphic.id}>
<img src={item.whyChooseIconGraphic.sourceUrl} alt={item.whyChooseIconGraphic.altText} />
<p>{item.whyChooseIconTitle}</p>
</div>
))}
</WhyChooseContent>
</WhyChooseSection>
))}
</>
)
}
export default WhyChooseIcons
My Homepage Code
import * as React from "react"
// import styled from "styled-components"
import { graphql } from 'gatsby'
import Seo from "../components/seo"
import Hero from '../components/heroComponent'
import { WhyChooseSection } from '../components/whyChooseIcons'
import { WhyChooseH2 } from '../components/whyChooseIcons'
import { WhyChooseContent } from '../components/whyChooseIcons'
import HomeProducts from '../components/homeProducts'
import HomeTestimonials from '../components/testimonials'
import HomeNewHomes from '../components/homeNewHomes'
import HomeFamilyTreatment from '../components/homeFamilyTreatment'
import HomeSolutions from '../components/homeSolutions'
import HomeMotorization from '../components/motorizationComps'
import HomeBrands from '../components/homeBrands'
import CTAOne from '../components/ctaOne'
const IndexPage = (hero) => {
const heroData = hero.data.homeHero
return (
<>
{heroData.edges.map(({ node }, index) => (
<Hero key={index} heroTitle={node.template.homePage.heroH1} heroSubTitle={node.template.homePage.heroParagraph} heroBg={node.template.homePage.heroBackground.gatsbyImage} heroBtnOneText={node.template.homePage.heroButton1Text} heroBtnOneURL={node.template.homePage.heroButton1Url} heroBtnTwoText={node.template.homePage.heroButton2Text} heroBtnTwoURL={node.template.homePage.heroButton2Url} />
))}
<WhyChooseSection>
<WhyChooseH2 displayH2="none"></WhyChooseH2>
<WhyChooseContent></WhyChooseContent>
</WhyChooseSection>
<HomeProducts />
<HomeTestimonials />
<HomeNewHomes />
<HomeFamilyTreatment />
<HomeSolutions />
<HomeMotorization />
<HomeBrands />
<CTAOne />
</>
)
}
export default IndexPage
export const Head = () => <Seo title="Home" />
export const HeroContent = graphql`
{
homeHero: allWpPage(filter: {template: {templateName: {eq: "Home Template"}}}) {
edges {
node {
template {
... on WpHomeTemplate {
homePage {
heroH1
heroParagraph
heroButton1Text
heroButton1Url
heroButton2Text
heroButton2Url
heroBackground {
gatsbyImage(placeholder: BLURRED, width: 1920)
altText
}
}
}
}
}
}
}
}
`
Since you only want to pass a prop into your <WhyChooseIcons> component and that the component itself renders its own content, there is no need to provide any children node to it in the consuming parent.
Simply update your <WhyChooseIcons> component to accept a prop that it will pass to its inner child. Let's name it displayH2 and we can simply pass it into the <WhyChooseH2> component by doing this: <WhyChooseH2 displayH2={displayH2}>. So your component definition now looks like this:
export function WhyChooseIcons({ displayH2 }) {
// Rest of the component logic here
return (
<>
{data.whyChooseIcons.nodes.map((node, index) => (
<WhyChooseSection key={index}>
<WhyChooseH2 displayH2={displayH2}>Why Choose Interior Details?</WhyChooseH2>
{/* Other content here */}
</WhyChooseSection>
))}
</>
)l
};
Then in the file where you consume this component, it is just a matter of passing "none" to the prop:
<WhyChooseSection displayH2="none">
HOWEVER this feel like a XY problem to me, because all you want is to control the conditional rendering of this component. What you can do is to create a prop on your component that determines whether <WhyChosseH2> should be rendered or not.
export const WhyChooseH2 = styled.h2`
text-align: center;
`
export function WhyChooseIcons({ shouldHideH2 }) {
return (
<>
{data.whyChooseIcons.nodes.map((node, index) => (
<WhyChooseSection key={index}>
{!shouldHideH2 && <WhyChooseH2>Why Choose Interior Details?</WhyChooseH2>}
{/* Other content here */}
</WhyChooseSection>
))}
</>
)
}
Then you can just control H2 rendering with a true/false boolean:
{/* To show it, just don't set the prop */}
<WhyChooseIcons />
{/* To hide it, both ways are valid */}
<WhyChooseIcons shouldHideH2 />
<WhyChooseIcons shouldHideH2={true} />

Unable to view custom sidebar component created with react router in storybook

I am quite new to React and have been trying to create a custom sidebar component. Based on my understanding by going through different tutorials, this is what I have so far:
react-router-dom version: ^6.3.0
storybook: ^6.1.17
These are my components
sidebar.jsx
const SidebarNav = styled.nav`
background: #15171c;
width: 250px;
height: 100vh;
display: flex;
justify-content: center;
position: fixed;
top: 0;
right: ${({ sidebar }) => (sidebar ? "0" : "-100%")};
transition: 350ms;
z-index: 10;
`;
const SidebarWrap = styled.div`
width: 100%;
`;
const Sidebar = () => {
const [sidebar, setSidebar] = useState(true);
return (
<>
<IconContext.Provider value={{ color: "#fff" }}>
<SidebarNav sidebar={sidebar}>
<SidebarWrap>
{sideBarData.map((item, index) => {
return <SubMenu item={item} key={index} />;
})}
</SidebarWrap>
</SidebarNav>
</IconContext.Provider>
</>
);
};
export default Sidebar;
sidebardata.jsx
export const sideBarData = [ {
title: "Question 4",
path: "/test"
},
// {
// title: "Question 5",
// path: "/testing"
// }
];
sidebarsubmenu.jsx
import React, { useState } from "react";
import { Link } from "react-router-dom";
import styled from "styled-components";
const SidebarLink = styled(Link)`
display: flex;
color: #e1e9fc;
justify-content: space-between;
align-items: center;
padding: 20px;
list-style: none;
height: 60px;
text-decoration: none;
font-size: 18px;
&:hover {
background: #252831;
border-left: 4px solid green;
cursor: pointer;
}
`;
const SidebarLabel = styled.span`
margin-left: 16px;
`;
const DropdownLink = styled(Link)`
background: #252831;
height: 60px;
padding-left: 3rem;
display: flex;
align-items: center;
text-decoration: none;
color: #f5f5f5;
font-size: 18px;
&:hover {
background: green;
cursor: pointer;
}
`;
const SubMenu = ({ item }) => {
const [subnav, setSubnav] = useState(false);
const showSubnav = () => setSubnav(!subnav);
return (
<>
<SidebarLink to={item.path}
onClick={item.subNav && showSubnav}>
<div>
{item.icon}
<SidebarLabel>{item.title}</SidebarLabel>
</div>
<div>
{item.subNav && subnav
? item.iconOpened
: item.subNav
? item.iconClosed
: null}
</div>
</SidebarLink>
{subnav &&
item.subNav.map((item, index) => {
return (
<DropdownLink to={item.path} key={index}>
{item.icon}
<SidebarLabel>{item.title}</SidebarLabel>
</DropdownLink>
);
})}
</>
);
};
export default SubMenu;
BookSideBarLayout.jsx
import React from 'react';
import Sidebar from './BookSideBar';
function Layout(props) {
return (
<div>
<div style={{display: "flex"}}>
<Sidebar/>
</div>
</div>
);
}
export default Layout;
BookSidebarRoutes.jsx
import React from "react";
import {BrowserRouter, Route,Routes} from "react-router-dom";
import Support from "./Support";
import Layout from "./BookSideBarLayout";
function MyRoutes() {
return (
<BrowserRouter>
<Layout/>
<Routes>
{/* <Route path="/" element={<Sidebar/>}/> */}
<Route path="/test" element={<Support/>}/>
</Routes>
</BrowserRouter>
);
}
export default MyRoutes;
The story that I created was as below
import { storiesOf } from '#storybook/react';
import StoryRouter from 'storybook-react-router';
import MyRoutes from '../../src/components/BookSidebarRoutes';
// export default {
// title: 'Side Bar',
// //decorators : [(Story) => (<MemoryRouter><Story/></MemoryRouter>)]
// };
storiesOf('Params', module)
.addDecorator(StoryRouter())
.add('params', () => (
<MyRoutes/>
));
export const Default = () => <MyRoutes />;
After I run my story above, I keep getting the error as below:
A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.**
I also tried Switch in the MyRoutes component but that too didn't work. Any guidance in this will be really helpful. Thank you in advance

React Navbar Hamburger Icon unable to be Positioned Absolutely to Right

I'm making a React navbar with a hamburger menu icon, but I cannot figure out why my icon cannot be positioned absolutely to the right. Chrome dev tools indicates that both Top and Right properties (as well as any other margin/padding properties) are invalid property values on my hamburger icon (a div element), though my nav menu itself is able to be positioned absolutely to the right.
Navbar.jsx:
import React, { useState } from 'react';
import NavIcon from './NavIcon';
import NavMenu from './NavMenu';
import './navbar.css';
const Navbar = () => {
const [isOpen, setIsOpen] = useState('false');
return (
<nav>
<NavIcon isOpen={isOpen} setIsOpen={setIsOpen} />
<NavMenu isOpen={isOpen} setIsOpen={setIsOpen} />
</nav>
);
};
export default Navbar;
NavMenu.jsx:
import React from 'react';
import NavItem from './NavItem';
import './navbar.css';
const NavMenu = ({ isOpen }) => {
const slideIn = {
transform: () => isOpen ? 'translateX(1)' : 'translateX(0)'
};
return (
<ul className='Navbar__menu' isOpen={isOpen} style={slideIn}>
<NavItem title='Home' />
<NavItem title='About' />
<NavItem title='Contact' />
</ul>
);
};
export default NavMenu;
NavIcon.jsx:
import React from 'react';
import './navbar.css';
const NavIcon = ({ isOpen, setIsOpen }) => {
const toXTop = {
transform: isOpen ? 'rotate(-45deg) translate(-5.25px, 6px)' : 'none'
};
const toXMid = {
opacity: isOpen ? '0' : '1'
};
const toXbottom = {
transform: isOpen ? 'rotate(45deg) translate(-5.25px, -6px)' : 'none'
};
return (
<div className='Navbar__icon' isOpen={isOpen} onClick={() => setIsOpen(!isOpen)}>
<div className='Navbar__icon--bars' style={toXTop} />
<div className='Navbar__icon--bars' style={toXMid} />
<div className='Navbar__icon--bars' style={toXbottom} />
</div>
);
};
export default NavIcon;
NavItem.jsx:
import React from 'react';
import './navbar.css';
const NavItem = ({ title }) => {
return (
<div className='Navbar__menu--item'>
{ title }
</div>
);
};
export default NavItem;
navbar.css:
.Navbar__icon {
display: block;
position: absolute;
top: 5;
right: 5;
z-index: 1;
cursor: pointer;
}
.Navbar__icon--bars {
width: 25px;
height: 4px;
background-color: #666;
border-radius: 5px;
margin: 4px 0;
transition: 0.2s;
}
.Navbar__menu {
position: absolute;
width: 15em;
height: auto;
right: 0;
list-style: none;
background-color: #000;
}
.Navbar__menu--item {
font: 1rem Arial, sans-serif;
color: #999;
margin: 1em;
cursor: pointer;
}
App.js just renders the Navbar.jsx component.
Any advice is appreciated. Thanks.
It seems that Top/Left/Right/Bottom property values in React do not support unitless numerical values, as this issue was resolved by adding px units to my values.

react router dom link with params dont allways work

I have written a simple search component with autosuggestion in react, it makes calls to the themoviedb. I am using react-router-dom and have defined a route param like this in app.js:
<Route path="/:id" component={SomeComponent} />
and the search component looks like this:
import React, { Component, Fragment } from "react";
import { Link } from "react-router-dom";
import styled from "styled-components";
import axios from "axios";
const SuggestionsResult = styled.ul`
text-decoration: none;
list-style: none;
text-align: left;
display: flex;
flex-direction: column;
width: 100%;
`;
const ResultItem = styled.li`
border-bottom: 0.0625rem solid hsla(0, 0%, 100%, 0.12);
padding: 10px 0 10px;
padding-left: 2px;
font-size: 1em;
cursor: pointer;
&:hover {
background: hsla(0, 0%, 100%, 0.12);
}
`;
export default class Search extends Component {
state = {
query: "",
results: [],
showSuggestions: false
};
handleInputChange = () => {
this.setState(
{
query: this.search.value
},
() => {
if (this.state.query && this.state.query.length > 1) {
if (this.state.query.length % 2 === 0) {
axios
.get(
`https://api.themoviedb.org/3/search/movie?api_key=${apiKey}&language=en-US&query=${
this.state.query
}&page=1&include_adult=false`
)
.then(({ data }) => {
this.setState({
results: data.results,
showSuggestions: !this.state.showSuggestions
});
});
}
} else if (!this.state.query) {
}
}
);
};
handleSuggestionClick = e => {
this.setState({ showSuggestions: false });
};
render() {
return (
<Fragment>
<input
placeholder="Search for a movie..."
ref={input => (this.search = input)}
onChange={this.handleInputChange}
/>
{this.state.showSuggestions && (
<Suggestions
results={this.state.results}
handleSuggestionClick={this.handleSuggestionClick}
/>
)}
</Fragment>
);
}
}
const Suggestions = ({ results, handleSuggestionClick }) => {
const options = results.map(r => (
<ResultItem key={r.id}>
<Link onClick={handleSuggestionClick} to={`/${r.id}`}>
{r.title}
</Link>
</ResultItem>
));
return <SuggestionsResult>{options}</SuggestionsResult>;
};
My problem is when clicking on the link it changes the url but it stays on the same site. If I dont use react-router-dom Link component and only use a elements it works fine but everthing re-renders.
** Update
My react-router code in app.js
<Router>
<Switch>
<Route exact path="/" component={MoviesList} />
<Route path="/:id" component={MovieDetail} />
</Switch>
</Router>
The Suggestions component doesn't receive the Router prop and hence it causes this issue. Wrap your Suggestions component with withRouter HOC. Also make sure that the Search component is rendered as a child or Router component
import React, { Component, Fragment } from "react";
import { Link, withRouter } from "react-router-dom";
import styled from "styled-components";
import axios from "axios";
const SuggestionsResult = styled.ul`
text-decoration: none;
list-style: none;
text-align: left;
display: flex;
flex-direction: column;
width: 100%;
`;
const ResultItem = styled.li`
border-bottom: 0.0625rem solid hsla(0, 0%, 100%, 0.12);
padding: 10px 0 10px;
padding-left: 2px;
font-size: 1em;
cursor: pointer;
&:hover {
background: hsla(0, 0%, 100%, 0.12);
}
`;
export default class Search extends Component {
state = {
query: "",
results: [],
showSuggestions: false
};
handleInputChange = () => {
this.setState(
{
query: this.search.value
},
() => {
if (this.state.query && this.state.query.length > 1) {
if (this.state.query.length % 2 === 0) {
axios
.get(
`https://api.themoviedb.org/3/search/movie?api_key=${apiKey}&language=en-US&query=${
this.state.query
}&page=1&include_adult=false`
)
.then(({ data }) => {
this.setState({
results: data.results,
showSuggestions: !this.state.showSuggestions
});
});
}
} else if (!this.state.query) {
}
}
);
};
handleSuggestionClick = e => {
this.setState({ showSuggestions: false });
};
render() {
return (
<Fragment>
<input
placeholder="Search for a movie..."
ref={input => (this.search = input)}
onChange={this.handleInputChange}
/>
{this.state.showSuggestions && (
<Suggestions
results={this.state.results}
handleSuggestionClick={this.handleSuggestionClick}
/>
)}
</Fragment>
);
}
}
const Suggestions = withRouter(({ results, handleSuggestionClick }) => {
const options = results.map(r => (
<ResultItem key={r.id}>
<Link onClick={handleSuggestionClick} to={`/${r.id}`}>
{r.title}
</Link>
</ResultItem>
));
return <SuggestionsResult>{options}</SuggestionsResult>;
});

Styled Components Selected Nav Item

I am trying to learn Styled Component's rendering based off props. I am just trying to create a simple Nav bar. Yes, I do realize that you can set links active by using React Router based off the location. This is more of just a learning experience for me.
class Nav extends Component {
constructor (props) {
super(props)
this.state = {
isActive: 0
}
this.handleClick = this.handleClick.bind(this)
}
handleClick (n) {
console.log('Hello There')
this.setState = {
isActive: n
}
}
render () {
const NAV = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
background-color: black;
`
const SPAN = styled.span`
font-size: 3.5vmin;
cursor: pointer;
color: white;
${props =>
props.selected &&
css`
color: cornflowerblue;
`}
`
const TEXT = styled.p``
return (
<NAV links={this.props.links}>
{this.props.links.map((i, ii) => (
<SPAN
onClick={e => this.handleClick(ii)}
key={ii}
selected={this.state.isActive === ii ? true : ''}
>
<TEXT>{i}</TEXT>
</SPAN>
))}
</NAV>
)
}
}
I am trying to make the link active by changing it's text color. When I map over the links I provide the Nav, if the index of the array if equal to the active state, I make that link active.
Then, onClick, I update the state's isActive to the index that was selected. Needless to say, it's not working. I guess the map's index is only available at render and not at the onClick event. I am not sure what to pass the handleClick function, however.
The App is rendering on my local environment just fine. I made a Codepen with the example, but it's not rendering on there. I've never used Codepen for React, here is the link: https://codepen.io/anon/pen/daqGQQ
Also, I realize I can use the className prop to make a CSS class to give the selected link an active status, but, I'd rather learn the 'styled components' way.
Any help would be much appreciated. Thanks
EDIT
Reformat based on comment:
import React, { Component } from 'react'
import styled, { css } from 'styled-components'
const NAV = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
background-color: black;
`
const SPAN = styled.span`
font-size: 3.5vmin;
cursor: pointer;
color: white;
${props =>
props.selected &&
css`
color: cornflowerblue;
`}
`
const TEXT = styled.p``
class Nav extends Component {
constructor (props) {
super(props)
this.state = {
isActive: 0
}
this.handleClick = this.handleClick.bind(this)
}
handleClick (e) {
console.log('Hello There')
console.log(e.target.key)
this.setState = {
isActive: 1
}
}
render () {
return (
<NAV links={this.props.links}>
{this.props.links.map((i, ii) => (
<SPAN
id={ii}
onClick={e => this.handleClick(e)}
key={ii}
selected={this.state.isActive === ii ? true : ''}
>
<TEXT>{i}</TEXT>
</SPAN>
))}
</NAV>
)
}
}
export default Nav
I figured it out by using e.currentTarget.textContent and then setting the state isSelected: e.currentTarget.textContent onClick. Code:
import React, { Component } from 'react'
import styled, { css } from 'styled-components'
const NAV = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
background-color: black;
`
const SPAN = styled.span`
font-size: 3.5vmin;
cursor: pointer;
color: white;
${props =>
props.selected &&
css`
color: cornflowerblue;
`}
`
const TEXT = styled.p``
class Nav extends Component {
constructor (props) {
super(props)
this.state = {
isSelected: 'Home'
}
this.handleClick = this.handleClick.bind(this)
}
componentDidMount () {}
handleClick (e) {
this.setState({
isSelected: e.currentTarget.textContent
})
}
render () {
return (
<NAV links={this.props.links}>
{this.props.links.map((i, ii) => (
<SPAN
id={ii}
onClick={e => this.handleClick(e)}
key={ii}
selected={this.state.isSelected === i ? true : ''}
>
<TEXT>{i}</TEXT>
</SPAN>
))}
</NAV>
)
}
}
export default Nav

Resources