alvvi
@alvvi
export default apathy;

Как правильно получить clientWidth DOM-элемента после рендеринга?

Есть компонент навигации, в данный момент он выглядит вот так:
spoiler
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
import styles from './Nav.styl';

export default class Nav extends Component {    
    state = {
        boundryOffset: 0,
        boundryWidth: 0
    }

    updateBoundry = (target) => {
        if (target && target.firstChild.classList.contains('active')) {
            this.setState((prevState) => ({
                ...prevState, 
                boundryOffset: target.firstChild.offsetLeft,
                boundryWidth: target.firstChild.clientWidth, 
            }))
        }
    }

    render() {
        return (
            <nav ref="nav" className={styles.nav}>
                <span 
                    style={{
                        transform: `translateX(${this.state.boundryOffset}px)`,
                        width: `${this.state.boundryWidth}px`
                    }}
                    className={styles.boundry}></span>
                <li className={styles.item} 
                    ref={this.updateBoundry}>
                    <NavLink exact className={styles.link} to='/'>Home</NavLink>
                </li>
                <li className={styles.item} 
                    ref={this.updateBoundry}>
                    <NavLink  exact className={styles.link} to='/training'>Decks</NavLink>
                </li>
            </nav>
        );
    }
}

Если кратко: я пытаюсь сделать перемещающийся элемент, который будет находится под активной ссылкой.

Как видно, при вызове ref-callback'a я проверяю содержит ли li активный линк и пытаюсь получить некоторые свойства с этого линка, а потом вызываю setState чтобы вызвать рендеринг и соответственно перемещение элемента boundry, однако проблема в том, что clientWidth возвращает 0, а offsetLeft непонятно откуда взявшиеся 32. Те же результаты я получаю при попытке выбрать эти элементы обычными селекторами в componentDidMount хуке, в остальных хуках и консоле элементы возвращают правильные значения.
вот, здесь при апдейте компонента все посчитается верно, а при маунтинге - нет(
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
import styles from './Nav.styl';

import ReactDOM from 'react-dom';

export default class Nav extends Component {
    constructor(props) {
        super();
    }
    
    componentDidUpdate() {
        this.updateBoundry();
    }

    componentDidMount() {
        this.updateBoundry();
    }

    updateBoundry = () => {
        const target = ReactDOM.findDOMNode(this).querySelector('.active');
        const boundry =  ReactDOM.findDOMNode(this).querySelector('.'+styles.boundry);

        
        if (target) {

            boundry.style.transform = `translateX(${target.offsetLeft}px)`
            boundry.style.width =  `${target.offsetWidth}px`

        }
    }

    render() {
        return (
            <nav ref="nav" className={styles.nav}>
                <span className={styles.boundry}></span>
                <li className={styles.item} >
                    <NavLink exact className={styles.link} to='/'>Home</NavLink>
                </li>
                <li className={styles.item}>
                    <NavLink  exact className={styles.link} to='/training'>Decks</NavLink>
                </li>
            </nav>
        );
    }
}


Использую stylus-loader, css-modules, postcss, если это важно.
  • Вопрос задан
  • 611 просмотров
Пригласить эксперта
Ответы на вопрос 1
KorniloFF
@KorniloFF Куратор тега JavaScript
Работаю по font-end / JS
element.getBoundingClientRect() - там есть все, что нужно.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы