OnScroll event firing without scrolling - Reactjs - reactjs

I have a div on which I've added onScroll and triggering a function on scroll event.
import React, { useRef } from 'react';
export const DemoComponent () => {
const myref = useRef(null);
const scrollEvent = () => {
//do something here
//Problem is that this event is triggering on load multiple times even when there is no scroll happening
};
return (
<div onScroll={scrollEvent} ref={myref}></div>
);
};
On load the scroll event triggers multiple times when there is no scrolling yet. Can't seem to figure out how to prevent this.

There must be something else causing that because, from the code you provided, the event only fires when the view has been scrolled. I added styling to get the scrollbar
export default class MyComponent extends Component {
scrollEvent = () => {
console.log("renders");
//do something here
//Problem is that this event is triggering on load multiple times even when there is no scroll happening
};
render() {
const style = {
width: "100px",
height: "100px",
overflowY: "scroll",
};
const innerDiv = {
height: "300px",
width: "100px",
background: "#efefef",
};
return (
<div style={style} onScroll={this.scrollEvent}>
<div style={innerDiv} />
</div>
);
}
}

Related

react How to hide the Card when another location is pressed

Developed with react and typescript.
Now the card is shown or hidden when you click on the div tag.
I want to hide the Card when it is displayed, even if another place other than the div tag is pressed.
import React, { FunctionComponent, useState } from 'react';
import { Card } from 'components/atoms/Card';
import { Display } from 'components/atoms/Display';
const Test: FunctionComponent = () => {
const [isDisplay, setIsDisplay] = useState(false);
const onClick = () => {
setIsDisplay(!isDisplay);
};
return (
<>
<div onClick={onClick} style={{ width: '100px', height: '100px' }}>
display Card
</div>
<Display enabled={isDisplay}>
<Card width={100} height={100}></Card>
</Display>
</>
);
};
export default Test;
Try this in your onClick method. It looks like you need to access the current state's value and update it.
setIsDisplay(state => !state);
It's explained here in the React docs.
https://reactjs.org/docs/hooks-reference.html#functional-updates

React useMeasure not working with nextJS?

I'm currently trying to animate a div so that it slides from bottom to top inside a card.
The useMeasure hook is supposed to give me the height of the wrapper through the handler I attached to it : <div className="desc-wrapper" {...bind}>
Then I am supposed to set the top offset of an absolutely positionned div to the height of its parent and update this value to animate it.
The problem is that when logging the bounds returned by the useMeasure() hook, all the values are at zero...
Here is a link to production exemple of the panel not being slided down because detected height of parent is 0 : https://next-portfolio-41pk0s1nc.vercel.app/page-projects
The card component is called Project, here is the code :
import React, { useEffect, useState } from 'react'
import './project.scss'
import useMeasure from 'react-use-measure';
import { useSpring, animated } from "react-spring";
const Project = (projectData, key) => {
const { project } = projectData
const [open, toggle] = useState(false)
const [bind, bounds] = useMeasure()
const props = useSpring({ top: open ? 0 : bounds.height })
useEffect(() => {
console.log(bounds)
})
return (
<div className="project-container">
<div className="img-wrapper" style={{ background: `url('${project.illustrationPath}') no-
repeat center`, backgroundSize: project.portrait ? 'contain' : 'cover' }}>
</div>
<div className="desc-wrapper" {...bind} >
<h2 className="titre">{project.projectName}</h2>
<span className="description">{project.description}</span>
<animated.div className="tags-wrapper" style={{ top: props.top }}>
</animated.div>
</div>
</div>
);
};
export default Project;
Is this a design issue from nextJS or am I doing something wrong ? Thanks
I never used react-use-measure, but in the documentations, the first item in the array is a ref and you are suppose to use it this way.
function App() {
const [ref, bounds] = useMeasure()
// consider that knowing bounds is only possible *after* the view renders
// so you'll get zero values on the first run and be informed later
return <div ref={ref} />
}
You did...
<div className="desc-wrapper" {...bind} >
Which I don't think is correct...

Reactjs autoscroll to bottom of container

I'm trying to make a basic chat application where the use enters a message, then it appears on the screen. Like a normal messaging system I'd like the scroll bar to be at the bottom point by default. I've attempted to that that with the code below.
Here is the sandbox:
https://codesandbox.io/s/unruffled-pasteur-nz32o
And the code:
import React, { Component } from "react";
export default class Messages extends Component {
setScroll() {
this.messagesEnd.scrollIntoView({ behavior: "auto" });
}
componentDidMount() {
this.setScroll();
}
componentDidUpdate() {
this.setScroll();
}
render() {
return this.props.messages.map(message => {
return (
<div>
<h2>{message.message}</h2>
<div
style={{ float: "left", clear: "both" }}
ref={el => {
this.messagesEnd = el;
}}
/>
</div>
);
});
}
}
It works fine, however if there is a scrollbar in a component outside that container it also sets that to the bottom as well. Is there any way I can only set the scroll bar of the container to bottom (independent of any other scroll bars on the screen)?
Update your setScroll to include block: 'end' as an option for scrollIntoView:
setScroll() {
this.messagesEnd.scrollIntoView({ behavior: "auto", block: "end" });
}
https://codesandbox.io/s/wispy-water-463xy

react-custom-scrollbars jumps to top on any action

I am using react-custom-scrollbars in a react web app because I need to have two independant scroll bars, one for the main panel and one for the drawer panel. My issue is that the content in the main panel is dynamic and whenever I take some action in the main panel that changes state the scroll bar jumps to the top of the panel again.
UPDATE:
I believe I need to list for onUpdate and handle the scroll position there. If it has changed then update if not do not move the position?
In code, I have a HOC call withScrollbar as follows:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import AutoSizer from 'react-virtualized-auto-sizer';
import { Scrollbars } from 'react-custom-scrollbars';
import { colors } from '../../theme/vars';
import { themes } from '../../types';
// This is a Higher Order Component (HOC) used to
// provide a scroll bar to other components
export default (ChildComponent, styling) => {
class ComposedComponent extends Component {
state = {
// position: ??
};
handleUpdate = () => {
//update position
//this.scrollbar.scrollToBottom();
};
render() {
return (
<AutoSizer>
{
({ width, height }) => (
<Scrollbars
style={{ width, height, backgroundColor: colors.WHITE, overflow: 'hidden', ...styling }}
onUpdate={() => this.handleUpdate()}
renderThumbVertical={props => <Thumb {...props} />}
autoHide
autoHideTimeout={1000}
autoHideDuration={200}
>
<ChildComponent {...this.props} />
</Scrollbars>
)
}
</AutoSizer>
);
}
}
return ComposedComponent;
};
const Thumb = styled.div`
background-color: ${props =>
props.theme.theme === themes.LIGHT ? colors.BLACK : colors.WHITE};
border-radius: 4px;
`;
in my MainView component I just wrap the export like this:
export default withScrollbar(LanguageProvider(connect(mapStateToProps, null)(MainView)));
I have read a few similar issues on this like this one: How to set initial scrollTop value to and this one scrollTo event but I cannot figure out how to implement in my case. Any tips or suggestions are greatly appreciated.
So I found a way to get this to work and it feels like a complete hack but I'm posting in hopes it might help someone else.
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import AutoSizer from 'react-virtualized-auto-sizer';
import { Scrollbars } from 'react-custom-scrollbars';
import { colors } from '../../theme/vars';
import { themes } from '../../types';
// This is a Higher Order Component (HOC) used to
// provide a scroll bar to other components
export default (ChildComponent, styling) => {
class ComposedComponent extends Component {
state = {
stateScrollTop: 0,
};
onScrollStart = () => {
if (this.props.childRef) { // need to pass in a ref from the child component
const { scrollTop } = this.props.childRef.current.getValues();
const deltaY = Math.abs(scrollTop - this.state.stateScrollTop);
if (deltaY > 100) { // 100 is arbitrary. It should not be a high value...
this.props.childRef.current.scrollTop(this.state.stateScrollTop);
}
}
};
handleUpdate = () => {
if (this.props.childRef) {
const { scrollTop } = this.props.childRef.current.getValues();
this.setState({ stateScrollTop: scrollTop });
}
};
render() {
return (
<AutoSizer>
{
({ width, height }) => (
<Scrollbars
ref={this.props.childRef}
style={{ width, height, backgroundColor: colors.WHITE, overflow: 'hidden', ...styling }}
onScrollStart={e => this.onScrollStart(e)}
onUpdate={e => this.handleUpdate(e)}
renderThumbVertical={props => <Thumb {...props} />}
autoHide
autoHideTimeout={1000}
autoHideDuration={200}
>
<ChildComponent {...this.props} />
</Scrollbars>
)
}
</AutoSizer>
);
}
}
return ComposedComponent;
};
const Thumb = styled.div`
background-color: ${props =>
props.theme.theme === themes.LIGHT ? colors.BLACK : colors.WHITE};
border-radius: 4px;
`;
I use this HOC like this:
create a ref for the component you want to use it with
pass the ref to the component that will use the HOC:
class SomeChildComponent extends Component {
...
viewRef = React.createRef();
...
render() {
return ( <MainView childRef={this.viewRef} />)
}
import and wrap the component
import withScrollbar from '../../hoc/withScrollbar';
...
export default withScrollbar(MainView);
I tried the above solution and it didn't seem to work for me.
However what did work was making sure that my child components inside Scrollbars were wrapped in a div with a height of 100%:
<Scrollbars>
<div style={{ height: '100%' }}>
<ChildComponent />
<ChildComponent />
</div>
</Scrollbars>

Semantic UI React: how to add a transition to Popup?

I'm building a "hovering" menu, using semantic-ui-react's Popup, and want to add a simple show-hide transition, how it can be done?
this is probably coming in too late for this specific OP, but might be useful for someone else trying to figure same out.
I believe you can use the TransionablePortal as shown in the example. Just for fun, I adapted that example to what I think you are trying to do:
import React, { Component } from 'react'
import { Button, Menu, TransitionablePortal } from 'semantic-ui-react'
export default class TransitionablePortalExamplePortal extends Component {
state = { open: false }
handleOpen = () => this.setState({ open: true })
handleClose = () => this.setState({ open: false })
render() {
const { open } = this.state
return (
<TransitionablePortal
closeOnTriggerClick
onOpen={this.handleOpen}
onClose={this.handleClose}
transition={{animation: "fade left", duration: 500 }}
openOnTriggerClick
trigger={
<Button circular basic
icon="ellipsis vertical"
negative={open}
positive={!open}
/>
}
>
<Menu vertical style={{ right: '1%', position: 'fixed', top: '0%', zIndex: 1000}}>
<Menu.Item>Menu Item 1</Menu.Item>
<Menu.Item>Menu Item 2</Menu.Item>
</Menu>
</TransitionablePortal>
)}}
You should be able to make the transition use onMouseEnter and onMouseLeave if you want same transition to be on hover, instead of on click.
You can find in their official documentation example where you can make custom style for popup
import React from 'react'
import { Button, Popup } from 'semantic-ui-react'
const style = {
borderRadius: 0,
opacity: 0.7,
padding: '2em',
}
const PopupExampleStyle = () => (
<Popup
trigger={<Button icon='eye' />}
content='Popup with a custom style prop'
style={style}
inverted
/>
)
export default PopupExampleStyle
You can try to add transition property here

Resources