Как правильно обновить classNames в React? - PullRequest
0 голосов
/ 08 января 2020

При прокрутке вниз я добавил и удалил определенные классы. Я хочу вернуть классы обратно на прокрутку вверх. Как это можно сделать, используя только ReactJS?

Я использовал прослушиватель событий для изменения класса.

Основная концепция заключается в том, что содержимое панели навигации должно отображаться в центре, когда мы прокручиваем вниз, имя веб-сайта, отображаемое в div, должно отображаться на панели навигации, а содержимое, расположенное посередине, должно сдвигаться влево, а div, отображающий имя веб-сайта, должно исчезать. И когда мы прокручиваем обратно до div с именем веб-сайта, все должно вернуться к тому же состоянию, которое было до прокрутки вниз.

import React, { Component } from 'react';
import '../Styles/Navbar.css';

export class Navbar extends Component {

  handleScrollToElement(event) {
    let linkPosition = document.querySelector('.collapse');
    let brandName = document.querySelector('.navbar-brand');
    if (window.pageYOffset > 250){
      linkPosition.classList.remove('justify-content-center');
      linkPosition.classList.add('justify-content-end');
      brandName.classList.remove('invisible');
      brandName.classList.add('visible');
    }
  }

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

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

  render() {
    return (
      <div>
        <nav className='navbar navbar-expand-sm bg-dark navbar-dark fixed-top'>
          <a className='navbar-brand invisible' href='#'>Website Name</a>
          <button className='navbar-toggler' type='button' data-toggle='collapse' data-target='#navbarSupportedContent' aria-controls='navbarSupportedContent' aria-expanded='false' aria-label='Toggle navigation'>
            <span className='navbar-toggler-icon'></span>
          </button>
          <div className='collapse navbar-collapse justify-content-center' id='navbarSupportedContent'>
            <ul className='navbar-nav'>
              <li className='nav-item active'>
                <a className='nav-link' href='#'>Home</a>
              </li>
              <li className='nav-item'>
                <a className='nav-link' href='#'>Item 2</a>
              </li>
              <li className='nav-item'>
                <a className='nav-link' href='#'>About Us</a>
              </li>
              <li className='nav-item'>
                <a className='nav-link' href='#'>Contact</a>
              </li>
            </ul>
          </div>
        </nav>
        <div className='container-fluid hpage'>
          <div className='inner'>
            <h1 className='htext' >WEBSITE TITLE</h1>
          </div>
        </div>
      </div>
    )
  }
}

export default  Navbar;

1 Ответ

0 голосов
/ 08 января 2020

Когда вы используете React. js, вам следует максимально избегать прямых манипуляций с DOM. Если вам действительно нужна ссылка на DOM, вы должны использовать ref .

Я бы установил classNames для linkPosition и brandName как состояние в constructor и обновил бы их в handleScrollToElement.

Всякий раз, когда эти переменные state изменяются, вызывается функция render, которая обновляет представление.

Поскольку событие scroll часто срабатывает в Некоторое время я беспокоился и о производительности. Поэтому я добавил в код shouldComponentUpdate , чтобы предотвратить повторную визуализацию неизмененного представления.

Можно также отменить вызов обработчика события прокрутки, вызываемого для уменьшения количества вызовов setState.

import React, { Component } from 'react';
import '../Styles/Navbar.css';

export class Navbar extends Component {
  constructor(props) {
    super(props);

    this.state = {
      linkPositionClassName: 'justify-content-center',
      brandNameClassName: 'invisible',
    };
  }

  handleScrollToElement(event) {
    if (window.pageYOffset > 250){
      this.setState({
        linkPositionClassName: 'justify-content-end',
        brandNameClassName: 'visible',
      });
    } else {
      this.setState({
        linkPositionClassName: 'justify-content-center',
        brandNameClassName: 'invisible',
      });
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    const { linkPositionClassName, brandNameClassName } = this.state;

    // component needs to re-render only when at least one of the state changes
    return nextState.linkPositionClassName !== linkPositionClassName || nextState.brandNameClassName !== brandNameClassName;
  }

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

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

  render() {
    return (
      <div>
        <nav className='navbar navbar-expand-sm bg-dark navbar-dark fixed-top'>
          <a className=`navbar-brand ${this.state.brandNameClassName}` href='#'>Website Name</a>
          <button className='navbar-toggler' type='button' data-toggle='collapse' data-target='#navbarSupportedContent' aria-controls='navbarSupportedContent' aria-expanded='false' aria-label='Toggle navigation'>
            <span className='navbar-toggler-icon'></span>
          </button>
          <div className=`collapse navbar-collapse ${this.state.linkPositionClassName}` id='navbarSupportedContent'>
            <ul className='navbar-nav'>
              <li className='nav-item active'>
                <a className='nav-link' href='#'>Home</a>
              </li>
              <li className='nav-item'>
                <a className='nav-link' href='#'>Item 2</a>
              </li>
              <li className='nav-item'>
                <a className='nav-link' href='#'>About Us</a>
              </li>
              <li className='nav-item'>
                <a className='nav-link' href='#'>Contact</a>
              </li>
            </ul>
          </div>
        </nav>
        <div className='container-fluid hpage'>
          <div className='inner'>
            <h1 className='htext' >WEBSITE TITLE</h1>
          </div>
        </div>
      </div>
    )
  }
}

export default Navbar;
...