4

I want to add the scrolling effect. At the start, the elements have the opacity: 0.2 property. When element is reached in the browser window, it is to replace the property with opacity: 1. At this moment, when I scroll, all elements change the property to opacity: 1. How to make this value when element is reached in the browser, the rest of the elements have the property opacity: 0.2

class QuestionListItem extends Component {
  constructor() {
    super();
    this.state = {
      opacity: 0.2,
    };
  }

  componentDidMount = () => {
    window.addEventListener('scroll', () => {
      this.setState({
        opacity: 1,
      });
    });
  };

  render() {
    const { question } = this.props;
    const { opacity } = this.state;
    return (
      <div>
        <li
          key={question.id}
          className="Test__questions-item"
          style={{ opacity: `${opacity}` }}
          ref={
            (listener) => { this.listener = listener; }
          }
        >
          <p>
            {question.question}
          </p>
          <QuestionAnswerForm />
        </li>
      </div>
    );
  }
}

I want effect like this https://anemone.typeform.com/to/jgsLNG

2 Answers 2

4

A proper solution could look like this. Of course, this is just a concept. You can fine-tune the activation/deactivation logic using props from getBoundingClientRect other than top (e.g. height, bottom etc). Important that you should not set the component's state on every single scroll event.

const activeFromPx = 20;
const activeToPx = 100;

class ScrollItem extends React.Component {
  state = {
    isActive: false
  }
  
  componentDidMount = () => {
    window.addEventListener('scroll', this.handleScroll);
    this.handleScroll();
  };
  
  handleScroll = () => {
    const { top } = this.wrapRef.getBoundingClientRect();
    if (top > activeFromPx && top < activeToPx && !this.state.isActive) {
      this.setState({ isActive: true });
    }
    if ((top <= activeFromPx || top >= activeToPx) && this.state.isActive) {
      this.setState({ isActive: false });
    }
  }
  
  setWrapRef = ref => {
    this.wrapRef = ref;
  }
  
  render() {
    const { isActive } = this.state;
    return (
      <div
        className={`scroll-item ${isActive && 'scroll-item--active'}`}
        ref={this.setWrapRef}
        >
        {this.props.children}
      </div>
    )
  }
}


class ScrollExample extends React.Component {  
  render() {
    return (
      <div className="scroll-wrap">
        <ScrollItem>foo</ScrollItem>
        <ScrollItem>bar</ScrollItem>
        <ScrollItem>eh</ScrollItem>
      </div>);
  }
}

ReactDOM.render(<ScrollExample />, document.getElementById('root'))
.scroll-wrap {
  height: 300vh;
  background: lightgray;
  padding-top: 55px;
}

.scroll-item {
  height: 60vh;
  background: lightcyan;
  margin: 10px;
  opacity: 0.2;
}

.scroll-item--active {
  opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Sign up to request clarification or add additional context in comments.

2 Comments

how did you set these numbers 20 and 100? Why these numbers?
it is just a quick example. The item is active if its top edge is between 20 and 100 px distance from top of viewport. But you should find out some more advanced method like this, considering the window height etc.
0

You can include an isInViewport-like implementation as this one: https://gist.github.com/davidtheclark/5515733 then use it on your component.

componentDidMount = () => {
  window.addEventListener('scroll', (event) => {
    if (isElementInViewport(event.target) {
      this.setState({
        opacity: 1,
      });
    }
  });
};

There's also read-to-use react-addons for this: https://github.com/roderickhsiao/react-in-viewport

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.