2

I am trying to have a Link, when clicked, auto-scroll to the position of component. It is currently working 1, though a type error "TypeError: this.props.parentMethod is not a function" is thrown after the link/scroll is successful.

I have a set of links in a Header component, where clicking the links would jump to the listed components on the same page (SPA). I was also trying to pass the functions between components, though the Link + Scroll won't function without part of this code 2.

Heres the layout I currently have, not sure what is causing this TypeError. I am only trying to make the link for /About work at the moment.

App.jsx:

import React, { Component } from 'react';
import { Route, Switch, BrowserRouter as Router} from 'react-router-dom';

import Header from './components/Header.jsx'
import Footer from './components/Footer.jsx'
import Main from './components/Main.jsx'
import About from './components/About.jsx'
import Content from './components/Content.jsx'
import Portfolio from './components/Portfolio.jsx'

import './assets/styles.css';

class App extends Component {
    constructor (props){
        super(props);
        console.log("app");
    }

    render() {
        return (
            <Router>
                <div className="Global">
                    <div className="BG-1">
                        <div className="Header"><Header/></div>
                        <div className="Main"><Main /></div>
                        <div className="About"><About/></div>
                    </div>

                    <div className="BG-2">
                        <div className="Content"><Content/></div>
                        <div className="Portfolio"><Portfolio /></div>
                    </div>

                    <div className="Footer"><Footer /></div>
                </div>

            </Router>
        );
    }
}

export default App;

Header.jsx:

import React, { Component} from 'react';
import { Collapse, Navbar, NavbarToggler, NavbarBrand, Nav, NavItem, NavLink } from 'reactstrap';
import { Route, Link, Switch, BrowserRouter as Router } from 'react-router-dom';

import App from '../App.jsx'
import About from '../components/About.jsx'
import '../assets/styles.css';

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faUserAstronaut } from '@fortawesome/free-solid-svg-icons'

class Header extends Component {

    constructor (props){
        super(props);
        console.log('header');
    }

    click = () => {
        console.log('The link was clicked.');
        this.props.parentMethod();
    }

    render() {
        return(
            <Router>
                <div>
                    <Navbar className="Header-header" light expand="md"> 
                            <Nav className="ml-auto" navbar>
                                <NavItem>
                                    <Link to='/#about' className="Header-link" onClick={this.click}><NavLink> About </NavLink></Link>
                                </NavItem>
                            </Nav>
                    </Navbar>
                </div>
            </Router>
        )
    }
}

export default Header;

About.jsx:

import React, { Component } from 'react';
import { Row, Col, Toast, ToastBody, ToastHeader } from 'reactstrap';

import Header from '../components/Header.jsx'
import '../assets/styles.css';

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faAngleDoubleDown } from '@fortawesome/free-solid-svg-icons'


class About extends Component {

    constructor (props){
        super(props);
        this.state = { currOpacity: 1 };
        console.log('about');
    }

    componentDidMount () { 
        window.onscroll =()=>{ 
            if (window.scrollY < 750){
                this.setState({currOpacity: 1})
            }
            if (750 <= window.scrollY){
                const newOpacity = (200 - ((Math.ceil(window.scrollY/ 25)*25) - 750))/200;
                this.setState({currOpacity: newOpacity})
            }
        }
    }

    newRef() {
        console.log("Yo dawg.");
    }

    render () {
        const opacity = Math.min(this.state.currOpacity, 1);
        // console.log("scrollY", window.scrollY, (200 - ((Math.ceil(window.scrollY/ 25)*25) - 750))/200)
        // console.log("opacity:", opacity)
        return (
            <div href='/#section-about'>
                <span className="Main-arrow" style={{ opacity }}>
                    <FontAwesomeIcon className="Main-arrow-icon" icon={faAngleDoubleDown} size="3x" />
                </span>
                <Row className="About-title-row">
                    <h1 className="About-title" id={'about'} parentMethod={this.newRef}>About Me</h1>
                </Row>
            </div>
        )
    }
}

export default About;

Please let me know if more code is needed, some irrelevant content was removed. Any help would be appreciated!

Anthony

1 Click Link to Scroll Method: Click link to scroll to specific section react.js

2 Parent method call from Child: React - Call parent method in child component

AnthonyT
  • 536
  • 1
  • 5
  • 14

1 Answers1

3

You are getting the type error because prop parentMethod is not passed to the Header component.

In your App.jsx file you need to pass a prop to Header Component like this <Header parentMethod={() => {}} /> then it won't through type error

and you have to create a method in App.jsx file which you want to perform like the one you have created in About.jsx

import React, { Component } from 'react';
import { Route, Switch, BrowserRouter as Router} from 'react-router-dom';

import Header from './components/Header.jsx'
import Footer from './components/Footer.jsx'
import Main from './components/Main.jsx'
import About from './components/About.jsx'
import Content from './components/Content.jsx'
import Portfolio from './components/Portfolio.jsx'

import './assets/styles.css';

class App extends Component {
    constructor (props){
        super(props);
        console.log("app");
    }
    newRef() {
        console.log("Yo dawg.");
    }

    render() {
        return (
            <Router>
                <div className="Global">
                    <div className="BG-1">
                        <div className="Header"><Header parentMethod={this.newRef}/></div>
                        <div className="Main"><Main /></div>
                        <div className="About"><About/></div>
                    </div>

                    <div className="BG-2">
                        <div className="Content"><Content/></div>
                        <div className="Portfolio"><Portfolio /></div>
                    </div>

                    <div className="Footer"><Footer /></div>
                </div>

            </Router>
        );
    }
}

export default App;

Update your Header.jsx file as below

  click = (link) => {
    console.log("The link was clicked.", this.props);
    this.props.parentMethod();
    window.location = link;
  };

and update the link as below

<Link to="/#about" className="Header-link" onClick={() => this.click('/#about')}>
  <NavLink> About </NavLink>
</Link>


sarabs3
  • 504
  • 7
  • 13
  • I tried this and the parentMethod is now passing correctly to
    , but now the ' Link to="/#about" ' part no longer works
    – AnthonyT Apr 29 '19 at 05:13
  • I have updated the answer and added Header.jsx code. Try now – sarabs3 Apr 29 '19 at 05:46
  • Thanks sarabs3, this is working great! I am now trying to extend this method to other components but only the link to the #about component will work. The other links won't move the window location to those components. I am wondering whether this is due to some state not being updated? – AnthonyT Apr 30 '19 at 03:08
  • For every link, you need to pass the URL to `this.click('/#about')` like in the example passed for about us. https://codesandbox.io/s/l5q1jq0lw9 Here is a code sandbox example I have created. It will surely help you – sarabs3 May 01 '19 at 07:28
  • Thanks, your codesandbox was very helpful. I noticed that the function newRef() and parentMethod() weren't needed for the routing and reference to work. I ended up removing these for the solution, but a good to-have for those who want to run some code on-click. – AnthonyT May 03 '19 at 02:41