Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get div's offsetTop positions in React

I am trying to implement a List view in React. What I am trying to achieve is that to store the list headers informations and register the components and register the scroll event. every time when user scroll the window, I'd like to take out the stored div and re-calculate the offsetTop data.

The problem now is that, I found the console just print out the initial value (the value is fixed and never changed) offsetTop data never change in onscroll function.

Anyone suggest how to get latest offsetTop from the _instances object?

import React, { Component } from 'react'; import ListHeader from './lib/ListHeader'; import ListItems from './lib/ListItems';  const styles = {   'height': '400px',   'overflowY': 'auto',   'outline': '1px dashed red',   'width': '40%' };  class HeaderPosInfo {   constructor(headerObj, originalPosition, originalHeight) {     this.headerObj = headerObj;     this.originalPosition = originalPosition;     this.originalHeight = originalHeight;    } }  export default class ReactListView extends Component {   static defaultProps = {     events: ['scroll', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll', 'resize', 'touchmove', 'touchend'],     _instances:[],     _positionMap: new Set(),     _topPos:'',     _topWrapper:''   }    static propTypes = {     data: React.PropTypes.array.isRequired,     headerAttName: React.PropTypes.string.isRequired,     itemsAttName: React.PropTypes.string.isRequired,     events: React.PropTypes.array,     _instances: React.PropTypes.array,     _positionMap: React.PropTypes.object,     _topPos: React.PropTypes.string,     _topWrapper: React.PropTypes.object   };    state = {     events: this.props.events,     _instances: this.props._instances,     _positionMap: this.props._positionMap,     _topPos: this.props._topPos   }    componentDidMount() {     this.initStickyHeaders();   }    componentWillUnmount() {    }    componentDidUpdate() {    }    refsToArray(ctx, prefix){     let results = [];     for (let i=0;;i++){       let ref = ctx.refs[prefix + '-' + String(i)];       if (ref) results.push(ref);       else return results;     }   }    initHeaderPositions() {     // Retrieve all instance of headers and store position info     this.props._instances.forEach((k)=>{       this.props._positionMap.add(new HeaderPosInfo(           k,            k.refs.header.getDOMNode().offsetTop,           k.refs.header.getDOMNode().offsetHeight         ));     });     let it = this.props._positionMap.values();     let first = it.next();     this.props._topPos = first.value.originalPosition;     this.props._topWrapper = first.value.headerObj;   }    initStickyHeaders () {     this.props._instances = this.refsToArray(this, 'ListHeader');     this.initHeaderPositions();      // Register events listeners with the listview div     this.props.events.forEach(type => {       if (window.addEventListener) {         React.findDOMNode(this.refs.listview).addEventListener(type, this.onScroll.bind(this), false);       } else {         React.findDOMNode(this.refs.listview).attachEvent('on' + type, this.onScroll.bind(this), false);       }     });   }    onScroll() {      // update current header positions and apply fixed positions to the top one     console.log(1);     let offsetTop  = React.findDOMNode(this.props._instances[0].refs.header).offsetTop;    }    render() {     const { data, headerAttName, itemsAttName } = this.props;     let _refi = 0;     let makeRef = () => {       return 'ListHeader-' + (_refi++);     };      return (       <div ref="listview" style={styles}>       {         Object.keys(data).map(k => {         const header = data[k][headerAttName];         const items  = data[k][itemsAttName];           return (             <ul key={k}>                    <ListHeader ref={makeRef()} header={header} />               <ListItems  items={items} />             </ul>           );         })       }       </div>     );   } } 

The whole source code is on Github, you can clone and compile it from here:

Github

like image 322
JavaScripter Avatar asked Sep 19 '15 11:09

JavaScripter


People also ask

How do you get the offsetTop in React?

To get a div's offsetTop positions in React, we can get it from the ref assigned to the element. to assign the inputRef to the input. Then we get the offsetTop property from the inputRef. current property which has the input element.

How do you get the position of REF IN React?

Getting the Size and Position You can use Element. getClientRects() and Element. getBoundingClientRect() to get the size and position of an element. In React, you'll first need to get a reference to that element.

How do you get the position of a component in React Native?

To get the position of an element with React Native, we can get it from the View 's onLayout callback. to add a View with the onLayout prop set to a function that gets the position values from the event. nativeEvent. layout property.

How do I get Element ID in React?

To get an element by ID in React: Set the ref prop on the element. Use the current property to access the element in the useEffect hook.


2 Answers

You may be encouraged to use the Element.getBoundingClientRect() method to get the top offset of your element. This method provides the full offset values (left, top, right, bottom, width, height) of your element in the viewport.

Check the John Resig's post describing how helpful this method is.

like image 153
Eugene Tiurin Avatar answered Sep 20 '22 10:09

Eugene Tiurin


I do realize that the author asks question in relation to a class-based component, however I think it's worth mentioning that as of React 16.8.0 (February 6, 2019) you can take advantage of hooks in function-based components.

Example code:

import { useRef } from 'react'  function Component() {   const inputRef = useRef()    return (     <input ref={inputRef} />     <div       onScroll={() => {         const { offsetTop } = inputRef.current         ...       }}     >   ) } 
like image 34
Pavel Ye Avatar answered Sep 19 '22 10:09

Pavel Ye