ReactJS change color of element on scroll and when certain position is reached

You could make your sections own components that keep a reference to their DOM element. Your Section component could then listen to a scroll event and invoke a callback that it has been given by the parent container when the top of your components DOM element reaches your fixed header.

Your Section component could look something like this.

class Section extends React.Component {

    ref = node => {
        this.ref = node;
        window.addEventListener('scroll', this.onScroll);
    }

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

    onScroll = event => {
        const {changeHeaderColor} = this.props;
        // calculate if the top value is inside your header by using the ref
        if (...) {
            changeHeaderColor();
        }
    }

    render() {
        const {id, children} = this.props;

        return (
            <div id={id} className="section" ref={this.ref}>{children}</div>
        );
    }
}

Then you could render your sections like this:

<Section id="section-1" changeHeaderColor={this.changeColor}> content here </Section>

The answer using hooks in React 16

import React from 'react'

export default Div => (){
  const [headerColor, setHeaderColor] = useState("white")


const listenScrollEvent = () => {
    window.scrollY > 10
      ? setHeaderColor("black")
      : setHeaderColor("white")
  }
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
  window.addEventListener("scroll", listenScrollEvent)
})

render() {

return(
  <div>
    <div id="header">
      <h1 style={{color: headerColor}}>
        This is the header
      </h1>
   </div>
   <div id="section_1" className="section">
      This is section 1
   </div>

   <div id="section_2" className="section">
      This is section 2
   </div>

   <div id="section_3" className="section">
      This is section 3
   </div>

   <div id="section_4" className="section">
      This is section 4
   </div>

   <div id="section_5" className="section">
      This is section 5
   </div>

 </div>
 )
 }
}

You could do this with React Hooks. This is what I did below.

Here is a Code SandBox to see all files. It has body.js and styles.css to help show changes on scroll. Below is the Header Component and its css file. Hope this Helps! (https://codesandbox.io/s/header-change-color-onscrolly-2z3vt)

// Header Component

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

import "./Header.css"

function Header2() {
const [header, setHeader] = useState("header")

const listenScrollEvent = (event) => {
  if (window.scrollY < 73) {
    return setHeader("header")
  } else if (window.scrollY > 70) {
    return setHeader("header2")
  } 
}

useEffect(() => {
  window.addEventListener('scroll', listenScrollEvent);

  return () =>
    window.removeEventListener('scroll', listenScrollEvent);
}, []);

  return (
    <header className={header}>
      <div className="logo">Logo</div>
      <ul className="links">
        <li className="link-item">home</li>
        <li className="link-item">about</li>
        <li className="link-item">join</li>
      </ul>
    </header>
  );
}

export default Header2;

css file.

// Styles header.css

.header {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  height: 120px;
  background-color: #fff;
  color: #333;
  transform: translateY(0);
  transition: transform 0.6s ease;
}

.header2 {
  position: fixed;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  height: 86px;
  background-color: gray;
  color: rosybrown;
  transform: translateY(10);
  transition: transform 6s ease;
  animation: myanimation 3s;
}
@keyframes myanimation {
  0% {
    background-color: transparent;
    color: transparent;
  }
  35% {
    background-color: gray;
    color: rosybrown;
  }
  100% {
    background-color: gray;
    color: rosybrown;
  }
}

.logo {
  margin: 0 24px;
  font-size: 28px;
  color: #f59596;
}

.links {
  padding: 0;
  margin: 0 24px;
}

.link-item {
  display: inline-block;
  margin: 0 12px;
  cursor: pointer;
}


Try this:

import React from 'react'

export default class Div extends React.Component{
  state = {
    color: 'white'
  }

  listenScrollEvent = e => {
    if (window.scrollY > 400) {
      this.setState({color: 'black'})
    } else {
      this.setState({color: 'white'})
    }
  }

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

  render() {
    return(
      <div>
        <div id="header">
          <h1 style={{color: this.state.color}}>
            This is the header
          </h1>
       </div>
       <div id="section_1" className="section">
          This is section 1
       </div>

       <div id="section_2" className="section">
          This is section 2
       </div>

       <div id="section_3" className="section">
          This is section 3
       </div>

       <div id="section_4" className="section">
          This is section 4
       </div>

       <div id="section_5" className="section">
          This is section 5
       </div>

     </div>
     )
   }
}

Basically we just use window.scrollY to know where has the user scrolled to.