I'm using react-intersection-observer in order to make some animations when the component is in view.
It works cool, but, when i try to go to a mobile screen, like, 633px width and 400px height, it does not work, and i really don't know why.
Let me show you the code
So, what i'm doing here, is that, i want to know when the user is seeing 45% of the component, but, it gives false always, is it because this component is quite big, probably its height is 750px or even more and the height of the screen of the phone is only 400px ? i don't know... I'm just trying to understand why it doens't work
const DifferentWorks = () => {
const [scrollY, setScrollY] = useState(0);
const { inView, ref } = useInView({ threshold: 0.45 });
useEffect(() => {
scrollYProgress.onChange(n => setScrollY(n));
}, [inView, scrollYProgress, scrollY]);
console.log(inView)
return (
<div ref={ref}>
<DifferentWorksHero>
</DifferentWorksHero>
</div>
);
};
export default DifferentWorks;
And let me show you what is the output of the console.log(inView)
I've scrolled all the component, from bottom to top, and this is the output
Always false..
What could be generating that error ? why it doesn't work when i change the size of the screen ?, specifally when the width is 663px and the height is under 500px
Related
Basically I want to render a div next to where I click.
I have done that works perfectly but my problem is when I scroll down its not following and render relevant to the page and not the screen.
Any work around my code if this so far:
const [position, setPosition] = useState([0,0])
const renderGuess = (event) =>{
if(guessed){
setPosition([0,0]);
setGuessed(false);
}else{
setPosition([event.clientX, event.clientY]);
setGuessed(true);
}
}
function Guess (position){
const {location} = position
console.log(location)
return(
<div id="guess-div" style={{top: `${location[1]}px`, left: `${location[0]}px`}}>
Note: I'm using react the render works fine only problem is when I scroll down it renders for example 150px from the top of the page not 150px from the screen.
I have tried 150 / 10, with vh and vw.
The event.clientX and event.clientY will get the viewport coordinates, not the document coordinates as you want.
You can replace the
setPosition([event.clientX, event.clientY]);
by
setPosition([event.pageX, event.pageY]);
to get the coordinates relative to the entire document instead.
References:
https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/clientX
https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageX
This is my first time working with react and we inherited code from another programmer who previously worked on the project. We have a new screen that has objects too big to fit within it and thus creates an unwanted scrollbar for the whole screen. This creates a weird glitch effect when we have any kind of animation going on and it's because the object on the page overflows of the bottom of the screen.
Do I need to call the update dimensions function on the screen in question or should I just update our default export to match 100% view height? I don't know how to do either, so if one method is preferred please explain how to do it. Thank you
import { Dimensions } from 'react-native';
let width = Math.round(Dimensions.get('window').width);
let height = Math.round(Dimensions.get('window').height);
window.onresize = updateDimensions;
export function updateDimensions() {
location.reload();
width = Math.round(Dimensions.get('window').width);
height = Math.round(Dimensions.get('window').height);
};
export default {
window: {
width,
height,
},
mobile: width < 400,
};
So, you need useState and useEffect to do that. Here is what I'd solve the problem:
const [dimensions, setDimensions] = useState({ window, screen });
useEffect(() => {
const subscription = Dimensions.addEventListener(
"change",
({ window, screen }) => {
setDimensions({ window, screen });
}
);
return () => subscription?.remove();
});
I've been trying to create a wrapper function so that i could load a sprite map into it and have an auto adjusting box that maintains the correct dimensions, rather than stretch the inital image that the sprites were made from. The problem occurs when the children of the wrapper are expanded, it causes the container box to expand but doesnt allow the wrapper to auto adjust its dimensions. This causes one of the borders, either top and bottom, or left and right to be larger/smaller than the other pair, which is not the desired effect.
The wrapper:
const AdaptBox = ({patternID, borderWidth, children}) =>{
const parentRef = useRef(null);
const [pixelHSize, setPixelHSize] = useState(borderWidth);
const [pixelWSize, setPixelWSize] = useState(borderWidth);
const imgs = SPRITE_PATTERNS[patternID];
useEffect ( () => {
console.log("use effect");
if(parentRef.current){
//useEffect hook to get the parents dimensions and then adjust ratio of wrapper
let parentHeight = parentRef.current.scrollHeight;
let parentWidth = parentRef.current.scrollWidth;
console.log(parentHeight);
console.log(parentWidth);
if(parentHeight<parentWidth){
console.log("wide scale");
setPixelHSize(((parentWidth/parentHeight)*borderWidth)/(parentWidth/parentHeight));
setPixelWSize(((parentHeight/parentWidth)*borderWidth));
}
else if(parentHeight>parentWidth){
console.log("tall scale");
setPixelHSize(((parentWidth/parentHeight)*borderWidth));
setPixelWSize(((parentHeight/parentWidth)*borderWidth)*(parentHeight/parentWidth));
}
else{
setPixelHSize(borderWidth);
setPixelWSize(borderWidth);
}
}
},[parentRef, borderWidth]);
return (
<Box img={imgs[4]} ref={parentRef}> //all styled comps
<BoxRow h={pixelHSize} w={100}>
<RowStuff.../>
</BoxRow>
<BoxRow h={100-(2*pixelHSize)} w={100}>
<VSide img={imgs[3]} h={100} w={pixelWSize}/>
<Back >
{children}
</Back>
<VSide img={imgs[5]} h={100} w={pixelWSize}/>
</BoxRow>
<BoxRow h={pixelHSize} w={100}>
<RowStuff.../>
</BoxRow>
</Box>
);
}
Implimentation of the wrapper:
...
<MainBodyContainer> //styled comp
<MainBody img={BGimg}> //styled comp
<AdaptBox patternID={0} borderWidth={1}> //Wrapper
<CoeffDisplay ></CoeffDisplay> //Child comp
</AdaptBox>
</MainBody>
</MainBodyContainer>
...
The "CoeffDisplay" contains a number of boxes that can be clicked on to expand.
Im open to another method of achieving this however i'm a fan of this wrapper style.
I've triple checked the simple maths but i think the issue is related to the use effect not being called on rerender.
Thanks for the help.
I'm trying to build a react Chat app and I was going to use the infinite scroll but it doesn't work the way I wanted it to. So I built one myself. I used useref to determine the height and if it reaches to the top it will add more chats. kinda like fb messenger's chat. The problem now is that when I add more chats, once it reaches the top, the scroll bar will continue to go up and not stick in place unlike how react-infinite scroll works.
May I know how I can go through this? Here is my code.
for the scroll:
const onScroll = () => {
if (topDiv.current) {
const { scrollTop, scrollHeight, clientHeight } = topDiv.current;
if(scrollTop === 0){
props.fecthMoreChat()
}
}
};
return(
<div id='scrollableDiv' ref={topDiv} onScroll={()=> onScroll()} style={{height:'100%', padding:'20px', display:'flex', flexDirection:'column', backgroundColor:'#efefef', overflowY:'scroll'}}>
{/* <div style={{visibility:'hidden'}} ref={topDiv}></div> */}
{currentChat.map((chat, index)=>{
return(
<div key={index} style={{textAlign:chat.sender===username?'right':'left'}}>
{chat.message}
</div>
)
})}
<div style={{visibility:'hidden'}} ref={botMsg}></div>
</div>
)
So the answer was actually pretty simple. I just took the current scroll height, saved it in a variable, then waited for the re-render and took the new scroll height. Basically, just subtract the old scroll height with the new scroll height and use that number to set scroll by using scrollTo(). Here is the code:
const onScroll = async () => {
if (chatDiv.current) {
const { scrollTop, scrollHeight, clientHeight } = chatDiv.current;
if(scrollTop === 0){
const pastScroll = scrollHeight
await props.fecthMoreChat()
const currentScroll = (await chatDiv.current.scrollHeight-pastScroll)
await chatDiv.current.scrollTo(0, currentScroll)
}
}
};
At work we're having some performance issues with rendering data tables so we've decided to try to virtualize a list "window". Essentially following the same idea as react-window, whereby you only render the sublist - the one showing on your viewport - of your data list.
For a myriad of reasons, we tried to implement the technique ourselves. In doing so, we learnt this is mostly done using position: absolute on each list item, which didn't really suitable for us. So we came up with the idea of just having two "wrapper" divs around the sublist we want to render.
Essentially box1 would have the height equal to the combined height of all the list items before our window and box2 would have the height of all the items after our window. Every time the user scrolls, we figure out which indices to render and adjust the box heights.
Unfortunately we ran into an issue where, when the user scrolls down, the scroll event keeps firing even after the user has stopped scrolling. This scrolls the list all the way to the end. It seems to work fine when scrolling up though, so we're really at a loss here. We couldn't figure out why it keeps firing.
Here's a link to an example. I just replaced all the list item logic with a fixed box for simplicity. I've also added a timeout to the scroll handler so the scrolling up behaviour is more noticeable, otherwise it's too fast and the red upper box is not noticeable.
Any help is much appreciated. Thanks in advance!
EDIT: We're actually using this in a <table> element, which means solutions based on css position property will not work, given that that property has undefined behaviour for table elements, and it breaks the standard table layout.
The problem is most likely caused by using the scrollTop value to change the height of the items which cause the scrollTop value to change and so on (maybe).
Here is the right way to do it https://codesandbox.io/s/react-hooks-playground-forked-97vsq
import React, { useState, useCallback } from "react";
import ReactDOM from "react-dom";
const ROW_HEIGHT = 25;
const App = (props) => {
const [items, innerHeight, onScroll] = useVirtualizedList({
numItems: 500,
itemHeight: ROW_HEIGHT,
windowHeight: ROW_HEIGHT * 5,
windowExtension: 0
});
return (
<div onScroll={onScroll} style={{ height: "500px", overflowY: "scroll" }}>
<div style={{
// position should be calculated depanding on the parent element position
position: 'fixed'
}}>{items}</div>
<div className="forceOverflow" style={{height: 500 * ROW_HEIGHT}}></div>
</div>
);
};
const useVirtualizedList = ({ numItems, itemHeight, windowHeight }) => {
const [scrollTop, setScrollTop] = useState(0);
const innerHeight = numItems * itemHeight;
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(
numItems - 1,
startIndex + Math.floor( windowHeight / itemHeight)
);
const onScroll = useCallback((e) => {
const currentScroll = e.currentTarget.scrollTop;
setScrollTop(currentScroll);
}, []);
const items = `${startIndex} --- ${endIndex}`
return [items, innerHeight, onScroll];
};
ReactDOM.render(<App />, document.getElementById("root"));