Anchor links in GatsbyJS + React - javascript

I have been stuck on this problem for a while now. I created a GatsbyJS project after I made my project in a normal create-react-app. Everything worked fine until I made some big changes to the code. This ruined my navigation - BUT NOT COMPLETELY! The logo navigation still works and the links in the footer, but not the NavBar items. I'm using the gatsby plugin: 'gatsby-plugin-anchor-links' (https://www.gatsbyjs.com/plugins/gatsby-plugin-anchor-links/).
Here is my NavBarItem code (component):
import React from "react"
import "../../Bulma.css"
import { Link } from "gatsby"
function NavBarItem(props) {
return (
<Link
className={"pl-6 pr-6 has-text-black navbar-item " + props.class}
to={"/#" + props.location}
>
{props.text}
</Link>
)
}
export default NavBarItem
Here is my NavBar component:
import React from "react"
import NavBarItem from "./assets/NavBarItem"
import "../Bulma.css"
import "./NavBar.css"
import { Link } from "gatsby"
import logo from "../../static/dronarfoton_logo.png"
class NavBar extends React.Component {
constructor(props) {
super(props)
this.state = {
isActive: true,
}
}
toggle() {
this.setState({ isActive: !this.state.isActive })
}
render() {
return (
<nav
className="navbar has-text-white has-background-grey-lighter has-navbar-fixed-top is-fixed-top"
role="navigation"
aria-label="main navigation"
>
<div className="navbar-brand">
<a href="#Top" className="navbar-item">
<img
alt="Logga som det står DrönarFoton på. Det visar en drönare och text."
src={logo}
width="112"
height="28"
/>
</a>
<a
role="button"
className={
this.state.isActive
? "navbar-burger burger"
: "is-active navbar-burger burger"
}
aria-label="menu"
aria-expanded={this.state.isActive ? "false" : "true"}
data-target="navbarBasicExample"
onClick={this.toggle.bind(this)}
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div
className={this.state.isActive ? "is-active navbar-menu" : "is-block"}
>
<div className="navbar-end">
<NavBarItem location="Top" text="Hem" />
<NavBarItem location="OmOss" text="Om oss" />
<NavBarItem location="Kontakt" text="Kontakt" />
<NavBarItem class="is-disabled" location="#" text="❌ Galleri ❌" />
</div>
</div>
</nav>
)
}
}
export default NavBar
Again, the 'navbar-brand' link WORKS but not the navbar items.
My thought was that it has something to do with how it's rendered, but I can't figure out how & why this is happening.
Another interesting part is that THE LINKS WORK IF I DISABLE JAVASCRIPT IN MY BROWSER
If someone has an idea of why this is happening. Please let me know.
Thanks //Gustav

You are using a prop location in your <NavBarItem> component but in the end, you are rendering a <Link>, that doesn't accept hashes (#) neither an anchor behavior. As you can see in <Link>'s API documentation (in-app navigation):
Neither <Link> nor navigate can be used for in-route navigation with a
hash or query parameter. If you need this behavior, you should either
use an anchor tag or import the #reach/router package—which Gatsby
already depends upon—to make use of its navigate function.
If you want to use an anchor link in your <NavBarItem>, you should use a regular <a> or using gatsby-plugin-anchor-links properly:
<AnchorLink
to="/about#team"
title="Check out our team!"
className="stripped"
stripHash
/>
Keep in mind that using a regular <a>, you will lose all the benefits on the #reach/routing and you will refresh the page completetly.

Related

How to add a link to another website after clicking on Card in React JS

Below is my code for Cards.js file, right now it's a card that you can click on and it links to the Services page with path ='/services' from within the same website, I would like to add a link to another website, how would I go about doing that? would I need to add an a href= link to Cards.js?
import React from 'react';
import CardItem from './CardItem';
import './Cards.css'
function Cards() {
return (
<div className='cards'>
<h1>Check out my Programming Portfolio Projects!</h1>
<div className='cards__container'>
<div className='cards__wrapper'>
<ul className="cards__items">
<CardItem
src={`${process.env.PUBLIC_URL}/images/ReactSocialPosts.jpg`}
text='hello testing 123'
label='This is a card'
path ='/services'
/>
</ul>
</div>
</div>
</div>
)
}
export default Cards;
Below is CardItem.js if needed
import React from 'react';
import { Link } from 'react-router-dom';
function CardItem(props) {
return (
<>
<li className='cards__item'>
<Link className='cards__item__link' to={props.path}>
<figure className='cards__item__pic-wrap' data-category={props.label}>
<img
src={props.src}
alt='Travel Image'
className="cards__item__img"
/>
</figure>
<div className='cards__item__info'>
<h5 className='cards__item__text'>{props.text}</h5>
</div>
</Link>
</li>
</>
);
}
export default CardItem;
I'm not sure, but I think that you would only have to create a second CardItem with its attribute path = complete link to external website.
Example :
<CardItem
src={`${process.env.PUBLIC_URL}/images/OtherImage.jpg`}
text='External website'
label='A label'
path ='https://externalwebsite.com'
/>
If you just want to simply link to another website then you can simply use an anchor tag, if you want to declare a Route from react-router-dom for that link to follow, you need to look at this post
As per documentation React-Router understands only internal paths. Then an anchor tag is needed. I would do a wrapper component for Link that chose if render an anchor or the router link object. Then use it instead of "Link".
Something like (code not tested):
const MyLink = ({path, children, ...props}) => {
const comp = path?.trim().substring(0,4) === "http" ? <a href={path}> : <Link to={path}>;
return <comp ...props>{children}</comp>
};

Components not working in Gatsby (showing as html tag)

So I wanted to add a navbar to a site I am building in Gatsby. I thought instead of having everything in index.js, I could split the html into different components. After doing that, I import that component into index.js but it doesn't work!
Here's an example:
import * as React from "react";
const navibar = () => (
<nav id="site-nav" className="navbar navbar-fixed-top navbar-custom">
<div className="container">
<div className="navbar-header">
<button
type="button"
className="navbar-toggle collapsed"
data-toggle="collapse"
data-target="#navbar-items"
aria-expanded="false"
>
<span className="sr-only">Toggle navigation</span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
</button>
</div>
// more code....
</nav>
);
export default navibar;
Then I import it,
//components
import { navibar } from "../components/navibar/navibar";
and use it as
export default IndexPage => () = {
return (
// some code...
<navibar />
// some more code...
)
}
Now the navbar doesn't actually shows up when I use gatsby develop, I checked the html using Chrome Devtools it looks like
<navibar></navibar>
Is this the wrong way to make up a component ? I am new to React & Gatsby.
You are exporting navibar as default component. so you need to change your import statement like this-
import Navibar from "../components/navibar/navibar";
Keep in mind that your react component name must be capitalized.
for eg.
export default IndexPage => () = {
return (
// some code...
<Navibar />
// some more code...
)
}
I think what's happening is that your component is named in lower case, try naming it and calling Navibar instead.
https://reactjs.org/docs/components-and-props.html#rendering-a-component

How to change the background-color of an element that is inside a GatsbyJS component, based on the page where I import the component?

It's the first time I'm building a website with GatsbyJS and I'm trying to build some components to use all over the site.
One of these components is the footer. I wrote its structure but I want to change the color of a <div> that is part of the footer based on which page am I visiting. I don't want the whole footer to change color, only this div that is part of the footer.
To be more accurate: if I'm visiting the Homepage I want this div to have an orange Background whereas if I'm inside the contact page I want it to have a blue background.
Is it possible?
This is part of the code of my footer (that is the footer.js gatsby component that I import in my pages):
<footer className={footerStyle.footer}>
<div className={footerStyle.parteSopra}>
<div className={footerStyle.parteSopra}>
<div className={footerStyle.ottanta}>
<h3 className={footerStyle.rimaniamo+ ' '+footerStyle.dimTitoli}>rimaniamo<br />in contatto</h3>
</div>
<div className={footerStyle.venti}>
</div>
</div>
<div className={footerStyle.parteSotto}>
<div className={footerStyle.ottanta+ ' '+footerStyle.boxFrecciaBlu}>
<div className={footerStyle.contieniFrecciaBlu}>
<img className={footerStyle.frecciaBlu} src={frecciaBlu} alt="Freccia giù" />
</div>
</div>
<div className={footerStyle.venti+ ' '+footerStyle.boxFbEInstaBlu}>
<div className={footerStyle.contieniFbBlu}>
<a href="https://it-it.facebook.com/DiamanteCalzature" target="_blank" rel="noopener noreferrer">
<img className={footerStyle.fbBlu} src={iconaFbBlu} alt="Facebook" />
</a>
</div>
<div className={footerStyle.contieniInstaBlu}>
<a href="https://instagram.com/diamantecalzature?igshid=cta3uh8iob7a" target="_blank" rel="noopener noreferrer">
<img className={footerStyle.instaBlu} src={iconaInstaBlu} alt="Instagram" />
</a>
</div>
</div>
</div>
</div>
<div id="coloreFootSotto" className={footerStyle.parteSotto+ ' '+footerStyle.coloreFooterSotto}>
<div className={footerStyle.ottanta}>
</div>
<div className={footerStyle.venti+ ' '+footerStyle.boxTornaSu}>
</div>
</div>
</footer>
I import it in my pages writing <Footer /> and I thought I could add an attribute, a prop, or something inside that tag to realize what I want. I need the div with Id id="coloreFootSotto" to have a different background-color based on the page I am visiting. At the moment I'm just manipulating the DOM in some pages to change the background-color but I was wondering if it is possible to do it with props or something like that (maybe not).
Does anyone know it?
Thank you
Gatsby uses reach router so you can use useLocation in your component and do something with the location.pathname for specific routes.
// Footer.js
import React from 'react';
import { useLocation } from "#reach/router"
import Container from 'components/Container';
const Footer = () => {
const {pathname} = useLocation()
console.log(pathname)
return (
<footer style={pathname=== '/' ? {backgroundColor: 'blue'} : null} >
<Container>
<p>© {new Date().getFullYear()}, My Gatsby Site</p>
</Container>
</footer>
);
};
export default Footer;
It's also worth mentioning that you can get location data from a gatsby page via its location prop.
Depending on how your app is structured, you could also get this data from your page component, and pass the relevant data down via props down through your component tree.
eg IndexPage > Layout > Footer
For multiple pages, you could do something like this.
// Footer.js
import React from 'react';
import { useLocation } from "#reach/router"
import Container from 'components/Container';
const pagesWithColoredFooter = ['/', '/page-2', 'page-3'];
const Footer = () => {
const {pathname} = useLocation()
console.log(pathname)
return (
<footer style={pagesWithColoredFooter.includes(pathname) ? {backgroundColor: 'blue'} : null} >
<Container>
<p>© {new Date().getFullYear()}, My Gatsby Site</p>
</Container>
</footer>
);
};
export default Footer;

Using React.JS with Materialize v1.0.0 unable to init JS

Been trying to convert several of our projects using materialize-css v1.0 using npm into react.js and having a heck of time doing so. I was wondering if anyone else has tried to tackle this as well and maybe came up with some solutions?
I am able to use the css portion just fine using the npm module and referencing it in the Index.js.
The problem I have is initializing the minified js with individual components but having no success. Here is the example one being the Index.js for css entry point and the sidebar component I am trying to get working using minified js. I also provided the App.js configuration in case anyone was curious. The plan was to break each part of this project into individual components but first just wanted to get the functionality of initializing the sidebar js first before doing so.
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import 'materialize-css/dist/css/materialize.min.css';
import App from './components/App';
ReactDOM.render(<App />, document.getElementById('root'));
App.js
import React, { Component } from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
// import Header from './header/Header';
// import Footer from './Footer';
import Landing from './landing/Landing';
import About from './About';
import Projects from './Projects';
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<div>
{/*<Header />*/}
<Route exact path="/" component={Landing} />
<Route exact path="/about" component={About} />
<Route exact path="/projects" component={Projects} />
{/*<Footer /> */}
</div>
</BrowserRouter>
</div>
);
}
}
export default App;
Landing.js
import React, { Component } from 'react';
import M from 'materialize-css/dist/js/materialize.min.js';
// import { Link } from 'react-router-dom';
import './Landing.css';
class Landing extends Component {
componentDidMount() {
console.log(M);
const sideNav = document.querySelector('.button-collapse');
console.log(M.Sidenav.init(sideNav, {}));
M.Sidenav.init(sideNav, {});
}
render() {
return (
<div className="main-header">
<div className="primary-overlay">
<div className="navbar-fixed">
<nav className="transparent">
<div className="container">
<div className="nav-wrapper">
<a href="#home" className="brand-logo">
TEST
</a>
<a data-activates="side-nav" className="button-collapse">
<i className="material-icons">menu</i>
</a>
<ul className="right hide-on-med-and-down">
<li>
Home
</li>
<li>
About
</li>
<li>
Testimonials
</li>
<li>
Contact
</li>
<li>
<a className="btn blue">Download</a>
</li>
</ul>
</div>
</div>
</nav>
</div>
{/* Side Nav: fixed navbars must go right underneath main nav bar */}
<ul id="side-nav" className="side-nav">
<h4 className="blue-grey darken-4 center">TEST</h4>
<li>
<a className="divider" />
</li>
<li>
Home
</li>
<li>
About
</li>
<li>
Testimonials
</li>
<li>
Contact
</li>
</ul>
{/*-- Showcase */}
<div className="showcase container">
<div className="row">
<div className="col s12 main-text">
<h5>You found the...</h5>
<h1>Right Place To Start</h1>
<p className="flow-text">
To take your business to the next level with our services that
have taken companies to the fortune 500
</p>
<a href="#about" className="btn btn-large white black-text">
Learn More
</a>
<a href="#contact" className="white-text">
<i className="material-icons medium scroll-icon">
arrow_drop_down_circle
</i>
</a>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Landing;
Here are some screen shots I am getting with errors in my console as well regarding the anchor tags (not sure how I work around this if its needed in the side bar). I am getting access to the sidebar as per the console.logs shown below.
​Hope someone else has encountered this problem already and can help...
Cheers!
[![enter image description here][3]][3]
The trigger button markup is incorrect. It has to be data-target and it has to have the class sidenav-trigger. Also the side nav has to have the classname sidenav. side-nav with a hyphen will not work:
<a href="#" data-target="side-nav" className="sidenav-trigger button-collapse">
<i className="material-icons">menu</i>
</a>
Also you should always use refs instead of querying the DOM yourself when working with react. Apply a ref callback to the sidenav element and then use it to initialize:
class Landing extends Component {
onRef = nav => {
this.nav = nav;
M.Sidenav.init(nav);
};
render() {
return (
{/* ... */}
<ul ref={this.onRef} id="side-nav" className="sidenav">
<li><a className="divider" /></li>
{/* ... */}
</ul>
{/* ... */}
);
}
}
Working example with your corrected markup:

How to implement share to twitter with react js

I want to let users share images from my website to twitter.
I used this module react-share to implement this.But it doesn't give an option to share images.
My code looks likes this.
import { ShareButtons, ShareCounts, generateShareIcon, } from 'react-share';
const {
FacebookShareButton,
GooglePlusShareButton,
LinkedinShareButton,
TwitterShareButton,
PinterestShareButton,
VKShareButton,
} = ShareButtons;
<TwitterShareButton
url={shareUrl}
title={title}
className="shareBtn col-md-1 col-sm-1 col-xs-1">
<a className="twitter"><i className="fa fa-twitter" aria-hidden="true"></i></a>
</TwitterShareButton>
Please help me fix this on how to share images to twitter.
Please add <TwitterIcon> in your code
<TwitterShareButton
url={shareUrl}
title={title}
className="Demo__some-network__share-button">
<TwitterIcon
size={32}
round />
</TwitterShareButton>
react-share does not support image uploading. You can only share url, title and hashtags with TwitterShareButton.
Main image of page will be showed when you add url.
Also your icon is missing, this is how you can add icon.
<TwitterShareButton url={url} title={title}>
<button className="btn btn-circle">
<i className="fab fa-twitter"> </i>
</button>
</TwitterShareButton>
You can not share rich content to twitter using this widget, only way is to host your image on static url and share that url via TwitterShareButton
Sample react-share code snippet at https://samvikshana.weebly.com/blog/react-share-social-share-widgets
Correct answer is that you need to pass a child (Icon) to the ShareButton and also IMPORT it.
Example:
import React, { Component } from "react";
import {
TwitterShareButton,
TwitterIcon,
} from "react-share";
class Quotes extends Component {
render() {
return( <div>
<TwitterShareButton
title="Hello"
url="https://stackoverflow.com/"
>
<TwitterIcon size={32} round />
</TwitterShareButton>
</div>
)
}
}
It's a very nice tool.

Categories

Resources