Update Style of a Component Onscroll in React.Js

Update style of a component onScroll in React.js

You should bind the listener in componentDidMount, that way it's only created once. You should be able to store the style in state, the listener was probably the cause of performance issues.

Something like this:

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
});
},

Update style on scroll event in React

You need add an eventlistener in
componentDidMount and store your value in state, you need to rerender your component onScroll,

componentDidMount = () => {
window.addEventListener('scroll', ()=>{
this.setState({
// your flags
});
});
};

Note: if you want to add event listener to your div, you can access to it by ref in react like this,

componentDidMount = () => {
this.listener.addEventListener('scroll', ()=>{
this.setState({
// your flags
});
});
};
render(){
return(
<div ref={(listener) => { this.listener = listener }}></div>
)
}

Toggle Class based on scroll React JS

One way to add a scroll listener is to use the componentDidMount() lifecycle method. Following example should give you an idea:

import React from 'react';
import { render } from 'react-dom';

class App extends React.Component {
state = {
isTop: true,
};

componentDidMount() {
document.addEventListener('scroll', () => {
const isTop = window.scrollY < 100;
if (isTop !== this.state.isTop) {
this.setState({ isTop })
}
});
}
render() {
return (
<div style={{ height: '200vh' }}>
<h2 style={{ position: 'fixed', top: 0 }}>Scroll {this.state.isTop ? 'down' : 'up'}!</h2>
</div>
);
}
}

render(<App />, document.getElementById('root'));

This changes the Text from "Scroll down" to "Scroll up" when your scrollY position is at 100 and above.

Edit: Should avoid the overkill of updating the state on each scroll. Only update it when the boolean value changes.

Changing styles when scrolling React

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>

How to add a ClassName and remove it onScroll event in React.JS?

add an event listener in your useEffect. when you scroll down the value of window.scrollY will increase such as 1, 2, ...100 .. (in px) and update your color in useState as per the window.scrollY. try something like this

const StyledBody = window.styled.div`
background: lightgray;
height: 5000px;
`;

const StyledText = window.styled.h4`
text-align: center;
width: 250px;
margin: auto;
line-height: 40px;
`;

const StyledHeader = window.styled.div`
background-color: ${props => props.color};
width: 100%;
height: auto;
position: fixed;
top: 0;
left: 0;
right: 0px;
padding: 0;
z-index: 10000;
transition: all 1s ease-in-out;
`;

const Header = () => {
const [color, setColor] = React.useState("rgba(17, 42, 107, 0.7)");

const handleScroll = React.useCallback((event) => {
let scrollTop = window.scrollY;

//console.log(scrollTop ); //1,2,...100,...200...etc (in px)

if (scrollTop >= 20 && scrollTop < 50) {
setColor("yellow");
}

if (scrollTop >= 50 && scrollTop < 90) {
setColor("red");
}

if (scrollTop >= 90 && scrollTop < 120) {
setColor("green");
}
if (scrollTop >= 120 && scrollTop < 150) {
setColor("blue");
}
if (scrollTop >= 150 && scrollTop < 180) {
setColor("violet");
}
if (scrollTop >= 180 && scrollTop < 210) {
setColor("purple");
}
});

React.useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll, false);
};
}, []);

return (
<StyledBody>
<StyledHeader color={color}>
<StyledText>My background color changes</StyledText>
</StyledHeader>
</StyledBody>
);
};

export default Header;

here is a working demo ..change the code as per your need.demo

Edit: I have added styled-components for you. check it out and let me know whether it works for you. to know more about these hooks go to useEffect and useCallback

Change style of header component on scroll on home page only in React.Js

You should create a method for handling scroll and refer it in both addEventListener and removeEventListener. But in your example, you are not referring it. You can use it like the below code sample.

And you should use a condition to match URL that works only on home page.


state = {
scrolled: false
};

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

handleScroll = () => {
const isTop = window.scrollY < 84
if (!isTop) {
this.setState({
scrolled: true
})
} else {
this.setState({
scrolled: false
})
}
})

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

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.

How can i manipulate DOM inside the onScroll event in ReactJS?

There are at least two reasons it didn't work:

  • See this question's answers; basically, getElementsByClassName returns an HTMLCollection, not a single element, but your commented-out code was treating it as though it were a single element.

  • If your component was ever re-rendered, it would be rendered in its default state, not the updated state you changed via the DOM

But that's not how you'd do it with React. Instead, you'd:

  1. have the button state (whether it should be block or not) held as state in your component;

  2. use that state when rendering the topbutton_button, setting its style or class accordingly; and

  3. update that state in your handleScroll handler

A couple of others notes:

  • You also need to remove your handler when the component is unmounting

  • You shouldn't use arrow functions for component lifecycle functions

  • You don't need to use bind on an arrow function (handleScroll for instance). Either make it an arrow function or use bind in the constructor to bind it.

Something along these lines, see the *** comments

import React from "react";
import "../assets/arrow-up.png";

// *** Reusable function to decide whether we're "at the top" or not
function bodyIsAtTop() {
return (
document.body.scrollTop <= 40 &&
document.documentElement.scrollTop <= 40
);
}

class TopButton extends React.Component {

constructor(props) {
super(props);
// *** Initial state
this.state = {
atTop: bodyIsAtTop()
};
// *** No need for the following if you use an arrow function
// this.handleScroll = this.handleScroll.bind(this);
}

// *** Don't make this an arrow, make it a method
componentDidMount() {
window.addEventListener("scroll", this.handleScroll, true);
};

// *** Need to unbind when unmounted
componentWillUnmount = () => {
window.removeEventListener("scroll", this.handleScroll, true);
};

handleClick = () => {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
};

handleScroll = () => {
// *** Update state (possibly; if the flag isn't different, this doesn't do anything)
this.setState({atTop: bodyIsAtTop()});
};

render() {
// *** Get the flag from state, use it below in style
const {atTop} = this.state;
return (
<div className="topbutton_container">
<button
style={{ display: atTop ? "none" : "block" }}
onClick={this.handleClick}
onScroll={this.handleScroll}
className="topbutton_button"
>
<img src={require("../assets/arrow-up.png")} />
</button>
</div>
);
}
}

export default TopButton;

There I've kept your arrow functions for handleScroll and handleClick. There's an argument for making them methods and using bind in the constructor instead, but it's mostly a style thing. (Well...style and it's easier to mock prototype methods for testing, which is a non-style reason for using prototype methods and bind.)



Related Topics



Leave a reply



Submit