Lz430
Lz430

Reputation: 327

How can I scroll to a div onClick using React?

I have a sticky navigation in this app I'm building using React. What I'm trying to figure out is how can I scroll to that div using an onClick? I'm using the window.scrollTo method.

The divs on the page have corresponding IDs to the anchor tags.

handleClick = e => {
    this.setState({
        activeSection: e.target.id,
    });
    let sections = document.querySelectorAll('.deal-details__container');

    window.scrollTo({
        top: 690,
        behavior: 'smooth',
    });
};

My markup looks like this:

<h6 className="section-header-overview text-center mb-0">
<a href="#overview" className={ this.state.activeSection === true ? 'active' : ''} onClick={() => this.handleClick('overview')}>
    Overview
</a>

Here is one of the components I need to scroll to:

import React from 'react';
import { dealType } from '../../../../core/types';
import SpecsGroup from './SpecsGroup';
import SpecsTabButton from './SpecsTabButton';
import { Row, Col, Container } from 'reactstrap';
import { groupBy, filter, map, toPairs, pipe, prop, zipObj } from 'ramda';



export default class Specs extends React.PureComponent {
    scrollRef = React.createRef();

    static propTypes = {
        deal: dealType.isRequired,
    };

    state = {
        activeTab: 'capabilities',
        activeCategory: null,
    };

    filterSpecs() {
        const groupByCategories = pipe(
            filter(item => {
                if (
                    this.state.activeTab === 'capabilities' &&
                    capabilitiesCategories.includes(item.category)
                ) {
                    return true;
                }

                if (
                    this.state.activeTab === 'features' &&
                    featuresCategories.includes(item.category)
                ) {
                    return true;
                }

                return false;
            }),
            groupBy(prop('category')),
            toPairs,
            map(zipObj(['category', 'values']))
        );


    return groupByCategories(this.props.deal.equipment);
}

toggleActiveTab(tab) {
    if (this.state.activeTab !== tab) {
        this.setState({
            activeTab: tab,
            activeCategory: null,
        });
    }
}

toggleActiveCategory(category) {
    if (this.state.activeCategory !== category) {
        this.setState({
            activeCategory: category,
        });
    } else {
        this.setState({
            activeCategory: null,
        });
    }
}

render() {
    if (
        !this.props.deal.equipment ||
        this.props.deal.equipment.length === 0
    ) {
        return false;
    }

    return (
        <div className="deal-details__container pt-5 pb-5" id="specs" ref={this.scrollRef}>
            <Container>
                <Row className="deal__section-heading" noGutters>
                    <Col>
                        <h3 className="text-center"> Specifications </h3>
                    </Col>
                </Row>
                <Row className="rounded bg-white shadow-sm" noGutters>
                    <Col>
                        <Row className="deal-details__specs-tabs" noGutters>
                            <SpecsTabButton
                                isActive={
                                    this.state.activeTab === 'capabilities'
                                }
                                label="Capabilities"
                                value="capabilities"
                                handleOnClick={this.toggleActiveTab.bind(
                                    this
                                )}
                            />
                            <SpecsTabButton
                                isActive={
                                    this.state.activeTab === 'features'
                                }
                                label="Features"
                                value="features"
                                handleOnClick={this.toggleActiveTab.bind(
                                    this
                                )}
                            />
                        </Row>
                        <SpecsGroup
                            deal={this.props.deal}
                            category={this.state.activeTab}
                            activeCategory={this.state.activeCategory}
                            specs={this.filterSpecs()}
                            toggleActiveCategory={this.toggleActiveCategory.bind(
                                this
                            )}
                        />
                    </Col>
                </Row>
            </Container>
        </div>
    );
}
 }

I'm still learning react and JS in general. So I may be doing this completely wrong. I've read about refs, but not sure if those would be better/worse.

Any and all help is appreciated!

Upvotes: 6

Views: 38140

Answers (2)

Shriyacodes
Shriyacodes

Reputation: 116

If the reference is for a class component present inside the parent container where the OnClick event is fired, you will need to pass the reference as props to the child component. And then, use 'ref' attribute in the main div of the component.

Upvotes: 0

Cat_Enthusiast
Cat_Enthusiast

Reputation: 15688

You can use React's ref system which gives you access to DOM elements and manipulation.

So in your code you can do something like this:

class myComponent extends React.Component{
    constructor(props){
       super(props)
       this.state = {
          field: value
       }
       //creates a reference for your element to use
       this.myDivToFocus = React.createRef()
    }

    handleOnClick = (event) => {
        //.current is verification that your element has rendered
        if(this.myDivToFocus.current){
            this.myDivToFocus.current.scrollIntoView({ 
               behavior: "smooth", 
               block: "nearest"
            })
        }
    }

    render(){
       return(
          <button onClick={this.handleOnClick}>Click me</button>
          <div ref={this.myDivToFocus}>
              Welcome to my section
          </div>

       )
    }

}

Upvotes: 21

Related Questions