4

Please do not mark as duplicate. It is similar to other questions, but different, because I'm asking where to put the code, not how to write.

I have this code, and want to detect which section is in view:

export default class Home extends React.Component {
    render() {
        return (
            <React.Fragment>
                <div className="col_first">
                    <Scrollspy id="menu_section"
                               items={['section_1', 'section_2', 'section_3', 'section_4', 'section_5']}
                               currentClassName="is-current" className="c_nav_menu" style={{marginTop: 100}}>
                        <li className="c_nav_menu_item"><a href="#section_1">1</a></li>
                        <li className="c_nav_menu_item"><a href="#section_2">2</a></li>
                        <li className="c_nav_menu_item"><a href="#section_3">3</a></li>
                        <li className="c_nav_menu_item"><a href="#section_4">4</a></li>
                        <li className="c_nav_menu_item"><a href="#section_5">5</a></li>
                    </Scrollspy>

                    <div>
                        <li className="lines_between_1"></li>
                        <li className="lines_between_2"></li>
                        <li className="lines_between_3"></li>
                        <li className="lines_between_4"></li>
                    </div>
                </div>
                <section className="row bg_double">
                    <div className="col-lg-1">
                    </div>
                    <div className="col-lg-11  s_anim">
                        <div className="full_screen" id="section_1">
                            <div className="row full_size">
                                <div className="col-lg-12 center_in_s1">
                                    <h1 className="text_s1 gradient_text">ZdajTo</h1>
                                    <p>korepetycje on-line</p>
                                </div>
                            </div>
                            <div className="icon_border_round">
                                <a href="#section_2"><img src={"/assets/images/ic_arrow_down_gradient.png"}/></a>
                            </div>
                        </div>

                        <div className="full_screen" id="section_2">
                            <div className="row full_size">
                                <div className="col-lg-6 center_in">
                                    <h1> elo elo 320 </h1>
                                </div>
                                <div className="col-lg-6 center_in">
                                    <h1>Przykładowy tekst</h1>
                                </div>
                            </div>
                            <div className="icon_border_round">
                                <a href="#section_3"><img src={"/assets/images/ic_arrow_down_gradient.png"}/></a>
                            </div>
                        </div>

                        <div className="full_screen" id="section_3">
                            <div className="row full_size">
                                <div className="col-lg-6 center_in">
                                    <h1> elo elo 320 </h1>
                                </div>
                                <div className="col-lg-6 center_in">
                                    <h1>Przykładowy tekst</h1>
                                </div>
                            </div>
                            <div className="icon_border_round">
                                <a href="#section_4"><img src={"/assets/images/ic_arrow_down_gradient.png"}/></a>
                            </div>
                        </div>

                        <div className="full_screen" id="section_4">
                            <div className="row full_size">
                                <div className="col-lg-6 center_in">
                                    <h1> elo elo 320 </h1>
                                </div>
                                <div className="col-lg-6 center_in">
                                    <h1>Przykładowy tekst</h1>
                                </div>
                            </div>

                            <div className="icon_border_round">
                                <a href="#section_5"><img src={"/assets/images/ic_arrow_down_gradient.png"}/></a>
                            </div>

                        </div>


                        <div className="full_screen" id="section_5">
                            <div className="row full_size">
                                <div className="col-lg-6 center_in">
                                    <h1> elo elo 320 </h1>
                                </div>
                                <div className="col-lg-6 center_in">
                                    <h1>Przykładowy tekst</h1>
                                </div>
                            </div>

                            <div className="icon_border_round">
                                <a href="#section_1"><img src={"/assets/images/ic_arrow_up_gradient.png"}/></a>
                            </div>
                        </div>
                    </div>
                </section>
            </React.Fragment>
        )
    }
};

I more or less know how to do it.

I found this question: Check if element is visible on screen

It has a great answer, which points to this fiddle: http://jsfiddle.net/t2L274ty/1/

Code from the answer

window.onscroll = function() {
  wrapper.style.backgroundColor = checkVisible(tester) ? '#4f4' : '#f44';
};

function checkVisible(elm) {
  var rect = elm.getBoundingClientRect();
  var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
  return !(rect.bottom < 0 || rect.top - viewHeight >= 0);
}

So my question is where should I put this kind of code? In componentDidMount() or maybe render()? What would be the React way of doing things?

Alex Ironside
  • 3,018
  • 4
  • 26
  • 74
  • 2
    https://stackoverflow.com/questions/29725828/update-style-of-a-component-onscroll-in-react-js I would check in a way similar to the answer of this question – Joe Jun 12 '18 at 13:00
  • 1
    `render()` may trigger multiple times, whereas `componentDidMount` only once, so Joe's link should help you. – Ionut Jun 12 '18 at 13:01
  • Although, you may want to throttle the scroll event with something like Rx.js or whatever – Joe Jun 12 '18 at 13:01
  • @Joe, just out of curiosity, how did you find the question you linked? While it does answer my question it's asking about something different, and I'd never think to search it like this. – Alex Ironside Jun 12 '18 at 13:12
  • 1
    I've implemented something similar in knockoutjs awhile ago. I search 'React onscroll' or something similar. – Joe Jun 12 '18 at 16:53
  • it is possible to do the same with Mutation Observer - https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver? – Webwoman Feb 14 '19 at 20:28

1 Answers1

4

You would put your event code in componentDidMount and also componentWillUnmount.

componentDidMount() {
   window.addEventListener('scroll', this.onWindowScroll);
}

componentWillUnmount() {
  window.removeEventListener('scroll, this.onWindowScroll);
}

onWindowScroll = debounce(() => { // assuming you're using https://babeljs.io/docs/plugins/transform-class-properties/
  console.log('Debounced scroll event');
}, 100)

If you want to only listen to the scroll event once and you have multiple of these components you can be a bit more clever about it but not sure of your use case.

Dominic
  • 48,717
  • 14
  • 109
  • 126