Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 362
Lz430 Avatar asked Jan 17 '19 22:01

Lz430


1 Answers

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>

       )
    }

}
like image 148
Chris Ngo Avatar answered Sep 28 '22 19:09

Chris Ngo