[javascript] React.js에서 컴포넌트 onScroll의 업데이트 스타일

React에서 시차 효과를 만들기 위해 창 스크롤에서 자체 스타일을 업데이트 해야하는 구성 요소를 만들었습니다.

컴포넌트 render메소드는 다음과 같습니다.

  function() {
    let style = { transform: 'translateY(0px)' };

    window.addEventListener('scroll', (event) => {
      let scrollTop = event.srcElement.body.scrollTop,
          itemTranslate = Math.min(0, scrollTop/3 - 60);

      style.transform = 'translateY(' + itemTranslate + 'px)');
    });

    return (
      <div style={style}></div>
    );
  }

React가 구성 요소가 변경되었음을 알지 못하므로 구성 요소가 다시 렌더링되지 않기 때문에 작동하지 않습니다.

itemTranslate구성 요소의 상태에서 값을 저장 setState하고 스크롤 콜백을 호출 하려고했습니다 . 그러나 이것은 매우 느리기 때문에 스크롤을 사용할 수 없게 만듭니다.

이 작업을 수행하는 방법에 대한 제안 사항이 있습니까?



답변

리스너는 componentDidMount한 번만 생성되는 방식으로 바인딩해야합니다 . 스타일을 상태로 저장할 수 있어야합니다. 리스너가 성능 문제의 원인 일 수 있습니다.

이 같은:

componentDidMount: function() {
    window.addEventListener('scroll', this.handleScroll);
},

componentWillUnmount: function() {
    window.removeEventListener('scroll', this.handleScroll);
},

handleScroll: function(event) {
    let scrollTop = event.srcElement.body.scrollTop,
        itemTranslate = Math.min(0, scrollTop/3 - 60);

    this.setState({
      transform: itemTranslate
    });
},


답변

https://facebook.github.io/react/docs/events.html#ui-eventsonScroll 에서 React 요소 의 이벤트에 함수를 전달할 수 있습니다 .

<ScrollableComponent
 onScroll={this.handleScroll}
/>

비슷한 또 다른 답변 : https : //.com/a/36207913/1255973


답변

반응 형 탐색 표시 줄을 만드는 나의 솔루션

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

componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll);
}
handleScroll(event) {
    if (window.scrollY === 0 && this.state.scrolling === true) {
        this.setState({scrolling: false});
    }
    else if (window.scrollY !== 0 && this.state.scrolling !== true) {
        this.setState({scrolling: true});
    }
}
    <Navbar
            style={{color: '#06DCD6', borderWidth: 0, position: this.state.scrolling ? 'fixed' : 'relative', top: 0, width: '100vw', zIndex: 1}}
        >

나에게 성능 문제가 없습니다.


답변

Austins 응답을 사용할 때 게으른 동작 / 성능 문제를 발견하고 주석에 언급 된 참조를 사용하는 예제를 원하는 사람을 돕기 위해 스크롤 업 / 다운 아이콘으로 클래스를 토글하는 데 사용한 예제는 다음과 같습니다.

render 메소드에서 :

<i ref={(ref) => this.scrollIcon = ref} className="fa fa-2x fa-chevron-down"></i>

핸들러 메소드에서 :

if (this.scrollIcon !== null) {
  if(($(document).scrollTop() + $(window).height() / 2) > ($('body').height() / 2)){
    $(this.scrollIcon).attr('class', 'fa fa-2x fa-chevron-up');
  }else{
    $(this.scrollIcon).attr('class', 'fa fa-2x fa-chevron-down');
  }
}

그리고 Austin이 언급 한 것과 같은 방식으로 처리기를 추가 / 제거하십시오.

componentDidMount(){
  window.addEventListener('scroll', this.handleScroll);
},
componentWillUnmount(){
  window.removeEventListener('scroll', this.handleScroll);
},

심판 에 대한 문서 .


답변

다음과 같이 true를 전달하지 않으면 이벤트 리스너를 성공적으로 추가 할 수 없습니다.

componentDidMount = () => {
    window.addEventListener('scroll', this.handleScroll, true);
},


답변

classNames , React 후크 useEffect , useStatestyled-jsx 를 사용하는 예제 는 다음같습니다 .

import classNames from 'classnames'
import { useEffect, useState } from 'react'

const Header = _ => {
  const [ scrolled, setScrolled ] = useState()
  const classes = classNames('header', {
    scrolled: scrolled,
  })
  useEffect(_ => {
    const handleScroll = _ => {
      if (window.pageYOffset > 1) {
        setScrolled(true)
      } else {
        setScrolled(false)
      }
    }
    window.addEventListener('scroll', handleScroll)
    return _ => {
      window.removeEventListener('scroll', handleScroll)
    }
  }, [])
  return (
    <header className={classes}>
      <h1>Your website</h1>
      <style jsx>{`
        .header {
          transition: background-color .2s;
        }
        .header.scrolled {
          background-color: rgba(0, 0, 0, .1);
        }
      `}</style>
    </header>
  )
}
export default Header


답변

후크

import React, { useEffect, useState } from 'react';

function MyApp () {

  const [offset, setOffset] = useState(0);

  useEffect(() => {
    window.onscroll = () => {
      setOffset(window.pageYOffset)
    }
  }, []);

  console.log(offset);
};