React Wait until transition end for vertical scroll - css

I'm trying to make vertical scroll page looks like fullpage.js with react
https://alvarotrigo.com/fullPage/
Page scroll works well but having hard time to prevent double scroll..
I want to make scroll doesn't work until finish move to next page.
Using setTimeout and clearTimeout works well but it has pre delay before moving pages.
I don't like that so tried to use onTransitionEnd to detect change but doesn't work well.
Currently my code is like this
const Container = () => {
const [index, setIndex] = useState(0);
const [isAnimating, setAnimating] = useState(false);
const ref = useRef<HTMLDivElement>(null);
const animatingRef = useRef(false);
const indexRef = useRef(0);
indexRef.current = index;
useEffect(() => {
if (!isAnimating) {
const updater = (e: WheelEvent) => {
setAnimating(true);
let dir = e.deltaY;
if (dir < 0) {
indexRef.current > 0 && setIndex(indexRef.current - 1);
} else {
indexRef.current < 2 && setIndex(indexRef.current + 1);
}
};
window.addEventListener('wheel', e => updater(e));
return () => {
window.removeEventListener('wheel', e => updater(e));
};
}
}, [isAnimating]);
useEffect(() => {
if (ref && ref.current) {
ref.current.style.transition = 'all 0.5s ease-in-out';
ref.current.style.transform = `translate3d(0,-${index * 100}%,0)`;
}
}, [index]);
return (
<Wrapper>
<ViewContainer ref={ref} onTransitionEnd={() => setAnimating(false)}>
<View color="orange" />
<View color="red" />
<View color="yellow" />
</ViewContainer>
</Wrapper>
);
};

Related

Flatlist Re rendering: VirtualizedList: You have a large list that is slow to update

I am using a functional component to render a flatlist, and when the list needs to re render it is doing so ineffeciently. I have tried to format the code better and implement React.memo, useMemo, useCallback, but I keep failing. I thought I implemented React.memo here but I must be doing something wrong, because I still get the warning in the terminal that "You have a large list that is slow.."
Any help implementing the proper methods to prevent unnecessary re renders would be greatly appreciated.
const MemoRender = React.memo(() => {
const renderItem = ({item, index}) => {
return (
<HStack space={2}>
<Center >
<Text >
{'Serial : '}
{item.Serial}
</Text>
<Text>
{'Type : '}
{item.Type}
</Text>
</Center>
<Center >
<Text>
{'Brand : '}
{item.Brand}
</Text>
<Text>
{'Model : '}
{item.Model}
</Text>
<Text>
{'Room : '}
{item.Room}
</Text>
</Center>
<Center>
<Button transparent icon onPress={() => editUser(item)}>
<Icon as={Ionicons} active name="create" />
</Button>
<Button transparent onPress={() => deleteUser(item)}>
<Icon as={Ionicons} active name="trash" />
</Button>
</Center>
</HStack>
);
};
const memoizedValue = useMemo(() => renderItem, [users]);
const [page,setPage] = useState(1);
const [users, setUsers] = useState([]);
const fetchMoreData = () => {
setPage((prev) => prev + 1);
}
useEffect(() => {
console.log('mounted');
//const userRef = firebase.database().ref('/users');
const userRef = firebase.database().ref('/users' + '/C Room');
const OnLoadingListener = userRef.on('value', (snapshot) => {
//setUsers([]);
const list = [];
snapshot.forEach(function (childSnapshot) {
list.push(childSnapshot.val());
});
setUsers(list);
});
const childRemovedListener = userRef.on('child_removed', (snapshot) => {
// Set Your Functioanlity Whatever you want.
//alert('Child Removed');
});
const childChangedListener = userRef.on('child_changed', (snapshot) => {
// Set Your Functioanlity Whatever you want.
// alert('Child Updated/Changed');
});
return () => {
userRef.off('value', OnLoadingListener);
console.log('unmounting...');
//userRef.off('child_removed', childRemovedListener);
// userRef.off('child_changed', childChangedListener);
};
}, []);
useEffect(()=> {
if(page){
}
},[page]);
const deleteUser = (Item) => {
firebase.database()
.ref('users/' + '/C Room'+ '/' + Item.Id)
.remove()
.then(() => {})
.catch((err) => {
console.log(err);
});
};
const deleteAllUsers = () => {
firebase.database()
.ref('users')
.remove()
.then(() => {
setUsers([]);
});
};
return (
<FlatList
data={users}
style={styles.scrollView}
renderItem={memoizedValue}
keyExtractor={(item,index) => index.toString()}
extraData={users}
onEndReachedThreshold={0.3}
onEndReached={fetchMoreData}
contentContainerStyle={{padding: 5,backgroundColor: "green"}}
getItemLayout={(_, index) => ({
length: 60 + 20, // WIDTH + (MARGIN_HORIZONTAL * 2)
offset: (60 + 20) * (index), // ( WIDTH + (MARGIN_HORIZONTAL*2) ) * (index)
index,})}
/>
)
}, [])
Shopify just released new package that implements Virtualised List and replacing FlatList with better performance. It is following best practices of optimisation. Please take a look and test: https://shopify.github.io/flash-list/

How to integrate React.memo into my Flatlist in React Native

I am having trouble optimizing my Flatlist due to re renders, and I have read that because I am using a function and not a class that I will need to make use of React.Memo
<FlatList
data={users}
style={styles.scrollView}
renderItem={renderItem}
keyExtractor={(item,index) => index.toString()}
extraData={users}
onEndReachedThreshold={0.3}
onEndReached={fetchMoreData}
contentContainerStyle={{padding: 5,backgroundColor: "green"}}
getItemLayout={(_, index) => ({
length: 60 + 20, // WIDTH + (MARGIN_HORIZONTAL * 2)
offset: (60 + 20) * (index), // ( WIDTH + (MARGIN_HORIZONTAL*2) ) * (index)
index,})}
/>
useEffect(() => {
//const userRef = firebase.database().ref('/users');
const userRef = firebase.database().ref('/users' + '/C Room');
const OnLoadingListener = userRef.on('value', (snapshot) => {
//setUsers([]);
const list = [];
snapshot.forEach(function (childSnapshot) {
list.push(childSnapshot.val());
});
setUsers(list);
});
const childRemovedListener = userRef.on('child_removed', (snapshot) => {
// Set Your Functioanlity Whatever you want.
//alert('Child Removed');
});
const childChangedListener = userRef.on('child_changed', (snapshot) => {
// Set Your Functioanlity Whatever you want.
// alert('Child Updated/Changed');
});
return () => {
userRef.off('value', OnLoadingListener);
userRef.off('child_removed', childRemovedListener);
userRef.off('child_changed', childChangedListener);
};
}, []);
useEffect(()=> {
if(page){
}
},[page]);
the following link gave me a solid lead and I was able to implement a basic react memo but I am having trouble understanding how to implement it in my flatlist. I need it very badly so I can prevent unnecessary re renders

change the id inside an svg on scroll at viewport in React

So I have an svg with an animation, but I want the animation to start when I'm scolled on viewport. I cant quite get there tho.
My code:
export const useScrollHandler = () => {
const [scroll, setScroll] = useState(1);
useEffect(() => {
const onScroll = () => {
const scrollCheck = window.scrollY > 100;
setScroll(scrollCheck);
};
document.addEventListener("scroll", onScroll);
return () => {
document.removeEventListener("scroll", onScroll);
};
}, [scroll, setScroll]);
return scroll;
};
then I add it on my svg component ( i wont put the whole svg cause its too long):
const ImageEssentials = (props) => {
const scroll = useScrollHandler();
<svg ...>
<g id={scroll ? "" : "Box1"}>
</svg>
}
So basicly when I scroll i want the svg group to get the id "Box1" that it has the animation.

Change background-color once scrolled with react?

I want to change the bg color of my navbar div once I scroll down. And if it's already at the top, I want to revert back to the original. I tried doing this following some code I got from a website.
I am using tailwind for CSS and React.
Is there a better way to do this? And is there some kind of fault with this code?
export default function Home(props) {
const [scrollPosition, setScrollPosition] = useState(0);
const [top, setTop] = useState(true)
const handleScroll = () => {
const position = window.scrollY;
setScrollPosition(position);
if (scrollPosition == 0) {
setTop(true)
} else if (scrollPosition > 10) {
setTop(false)
} else if (scrollPosition < 10) {
setTop(true)
}
}
useEffect(() => {
window.addEventListener('scroll', handleScroll)
return () => {
window.removeEventListener('scroll', handleScroll)
}
})
return (
<div className={`${top ? 'bg-blue-500' : "bg-red-500"}`}>
</div>
);
}

react photoswipe gallery of thumbnails will not display as grid

I'm using photoswipe gallery.
When I do so, I get all the thumbnails in a single line... I would like them to fill the page like a grid.
Below is my react component code. I have noticed that if I go to each thumbnail in dev tools->inspect and change display to 'inline' I don't end up with a line break after/before each. It still looks garbage because lack of frames and other things, However, I don't know how or where to modify the look or styling of the thumbnails put that in my code.
import { PhotoSwipeGallery } from 'react-photoswipe-2';
const useStyles = makeStyles((theme) => ({
loadingPaper: {
margin: "auto",
width: '50%',
padding: '10px',
marginTop: "50px"
}
}));
function FrameViewer(props) {
const classes = useStyles();
let { cameraAccessor } = useParams();
const [frames, setFrames] = useState([]);
const [isGalleryOpen, setIsGalleryOpen] = useState(false);
const [imgGalleryH, setGalleryImgH] = useState(0);
const [imgGalleryW, setGalleryImgW] = useState(0);
const [cameraID, setCameraID] = useState("");
const { cameras } = props;
async function fetchCameraData(cameraAccessor) { // TODO: check if already loading before running. // code to get filenames and what not
}
useEffect(() => {
// code to lead camera data
}, [cameraAccessor]);
const getThumbnailContent = item => (
<img src={item.thumbnail} width={120} height={90} alt="" />
);
let cam = cameras[cameraID];
if (cam) { // Photoswipe requires a Height and Width ... so we need to load the first image and see how big before we can incept Photoswipe.
var img = new Image();
img.onload = function () {
setGalleryImgH(img.height);
setGalleryImgW(img.width);
}
img.src = "https://apps.usgs.gov/sstl/media/cameras/" + cameraFolderName(cam) + "/" + cameraFolderName(cam) + MOST_RECENT_FRAME_SUFFIX;
}
return (
<React.Fragment>
{cam && frames && frames.length && imgGalleryH > 0 && imgGalleryW > 0
? <PhotoSwipeGallery
items={frames.map((filename) => {
return {
src: 'https://example.com/media/cameras/' + cameraFolderName(cam) + '/' + filename,
thumbnail: 'https://example.com/media/cameras/' + cameraFolderName(cam) + '/' + filename,
w: imgGalleryW,
h: imgGalleryH,
title: filename.replace("_overlay.jpg", "").split("___")[1].replace("_", " ")
}
})}
options={{
closeOnScroll: false
}}
thumbnailContent={getThumbnailContent}
isOpen={isGalleryOpen}
onClose={() => setIsGalleryOpen(false)}
/>
: <Paper elevation={5} className={classes.loadingPaper}><Typography color="textSecondary" align='center'>loading...</Typography></Paper>
}
</React.Fragment >
);
}
Edit your CSS. Try overriding the display property at the container level (.pswp-thumbnails):
.pswp-thumbnails
{
display: flex;
}
... OR at the thumbnail level (.pswp-thumbnail):
.pswp-thumbnail {
display: inline-block;
}

Resources