I am trying to use links in my header to scroll to different parts of my App with scrollIntoView. The header is a child of App. I am getting a TypeError saying the variable I am trying to save the id to is undefined. Can someone please help me to determine what I am doing wrong? I think I may have to use ComponentDidMount, but I'm not sure how to do it, if that is even the fix. I am going to have to do this with all my header links.
//ERROR bundle.js:152 Uncaught TypeError: Cannot read property 'scrollIntoView' of null at App.getScrollLocations (bundle.js:152) at onClick (bundle.js:19957) at Object.ReactErrorUtils.invokeGuardedCallback (bundle.js:4660) at executeDispatch (bundle.js:4460) at Object.executeDispatchesInOrder (bundle.js:4483) at executeDispatchesAndRelease (bundle.js:3913) at executeDispatchesAndReleaseTopLevel (bundle.js:3924) at Array.forEach () at forEachAccumulated (bundle.js:4760) at Object.processEventQueue (bundle.js:4129) ///////
//App
class App extends Component {
constructor(props) {
super(props);
this.closeModal = this.closeModal.bind(this);
this.openModal = this.openModal.bind(this);
this.getScrollLocations = this.getScrollLocations.bind(this);
this.state = {
open: false,
projects: Service,
selectedProject: Service[0]
}
}
closeModal(event) {
this.setState({open: false});
}
openModal(project) {
this.setState({
open: true,
selectedProject: project
});
}
///////////// scroll function //////////////
getScrollLocations() {
const whatIDo = document.getElementById('.whatIdo');
console.log(whatIDo)
whatIDo.scrollIntoView();
}
render() {
const show = {
display: 'block'
};
const hide = {
display: 'none'
};
return (
<div>
<div style={this.state.open === false ? hide : show}>
<Modal
value={this.state.open}
closeModal={this.closeModal}
project={this.state.selectedProject}
/>
</div>
<Header
//////////// FUNCTION PASSED TO HEADER ///////////////
getScrollLocations={this.getScrollLocations}
/>
<Intro />
/////////////// ELEMENT I AM TARGETING /////////////////
<WhatIDo id="whatIDo" />
<WhoIAm />
<Gallery
value={this.state.open}
projects={this.state.projects}
openModal={this.openModal}
/>
<Contact />
<Footer />
</div>
);
}
}
//Header
const header = (props) => {
console.log(props);
return (
<div className="header">
<div className="header-name">
XXXXXXX XXXXXXX
</div>
<div className="header-links">
<ul>
<li>Intro</li>
<li
///////////// FUNCTION CALL ON CLICK /////////////////
onClick={() => props.getScrollLocations()}
>What I do</li>
<li>Who I am</li>
<li>My Work</li>
<li>Contact</li>
</ul>
</div>
</div>
)
}
scrollIntoView() The Element interface's scrollIntoView() method scrolls the element's ancestor containers such that the element on which scrollIntoView() is called is visible to the user.
To scroll to an element on click in React:Set a ref prop on the element you want to scroll to. Set the onClick prop on the other element. Every time the element is clicked, call the scrollIntoView() method on the ref object.
Scroll to an Element With the React Refs (References): The most simple way is to use ref to store the reference of the element that you want to scroll to. And call myRef. current. scrollIntoView() to scroll it into the view.
I used the following module to achieve this in react:
https://www.npmjs.com/package/scroll-into-view-if-needed
It works much as you'd expect using in-page anchor links and can be used with react-router without problems.
import React from 'react';
import PropTypes from 'prop-types';
import scrollIntoViewIfNeeded from 'scroll-into-view-if-needed';
/*
SCROLL INTO VIEW
Purpose:
This modular component enables hash links
eg. (www.xyz.com/somepage#someID)
and plays nice with react router 4
Usage:
Wrap this component around a single div with an ID
Example:
<ScrollIntoView id={this.props.location.hash}>
<div id="someID">
... loads of content...
</div>
</ScrollIntoView>
<a href="/somepage#someID"> IN-PAGE ANCHOR </a>
*/
class ScrollIntoView extends React.Component {
componentDidMount() {
this.scroll();
}
componentDidUpdate() {
this.scroll();
}
scroll() {
const { id } = this.props;
//console.log('ID is: '+id);
if (!id) {
return;
}
const element = document.querySelector(id);
if (element) {
// this just jumps to the element
// see support:
//element.scrollIntoView({block: "end", behavior: "smooth"});
//If Firefox...
if (navigator.userAgent.indexOf("Firefox") > 0) {
//...use native smooth scrolling.
element.scrollIntoView({block: "end", behavior: "smooth"});
// If its any other browser, use custom polyfill...
}else{
//... luckily I have this handy polyfill...
scrollIntoViewIfNeeded(element, false, {
duration: 150
});
// (⌐■_■
}
}
}
render() {
return this.props.children;
}
}
ScrollIntoView.propTypes = {
id: PropTypes.string.isRequired,
children: PropTypes.oneOfType([
PropTypes.array.isRequired,
PropTypes.object.isRequired
])
};
export default ScrollIntoView;
Here is an example of that in action: https://anthonycregan.co.uk/portfolio
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With