简体   繁体   English

如何正确更新 React 中的 classNames?

[英]How to update classNames in React properly?

On scroll down I have added and removed certain classes.向下滚动时,我添加和删除了某些类。 I want to revert the classes back on scroll up.我想在向上滚动时恢复课程。 How can it be done using only ReactJS?如何仅使用 ReactJS 来完成?

I have used the event listener to change the class.我已经使用事件侦听器来更改类。

The main concept is the content of the navbar should be displayed in the center, when we scroll down the website name which is displayed in a div should be displayed on the navbar and the content which is placed in the middle, should shift to the left and the div which displays the website name should disappear.主要概念是导航栏的内容应该显示在中心,当我们向下滚动时,显示在div中的网站名称应该显示在导航栏上,放置在中间的内容应该向左移动并且显示网站名称的 div 应该消失。 And when we scroll back up to the div with the website name, everything should come back to the same as it was before scrolling down.当我们向上滚动到带有网站名称的 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;

When you use React.js, you should avoid direct DOM manipulation as much as possible.使用 React.js 时,应尽量避免直接操作 DOM。 If you really need a reference to a DOM, you should use ref instead.如果您确实需要对 DOM 的引用,则应改用ref

I would set classNames for linkPosition and brandName as state in constructor and update them in handleScrollToElement .我会设置classNameslinkPositionbrandName在状态constructor和更新它们handleScrollToElement

Whenever those state variables are changed, the render function will be called and will update the view.每当更改这些state变量时,将调用render函数并更新视图。

Since scroll event fires a lot in short amount of time, I was worried about the performance issue as well.由于scroll事件在短时间内触发了很多,我也担心性能问题。 So I added shouldComponentUpdate in the code to prevent re-rendering the unchanged view.所以我在代码中添加了shouldComponentUpdate以防止重新渲染未更改的视图。

You can also consider to debounce the scroll event handler function to be called to reduce the amount of calling the setState .您也可以考虑对要调用的滚动事件处理函数进行 debounce,以减少调用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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM