this is my table code in AntD, On pagination clicked I want it to scroll to page top. I tried using BackTop but I couldn't figure out how to do that with pagination
const GenericTable = props => {
const { withHeader, pagination, showTable, error } = props;
return (
<Fragment>
{withHeader && <TableHeader {...props} />}
{showTable && (
<CustomTable
{...props}
pagination={{
...pagination,
showTotal,
}}
/>
)}
<TableFooter>{<Error>{error}</Error>}</TableFooter>
</Fragment>
);
};
GenericTable.defaultProps = {
pagination: {
pageSize: 10,
},
};
Antd's table have a onChange method, by using that you can scroll to top by java script.
use
document.body.scrollTop = 0; // For Safari
document.documentElement.scrollTop = 0;
CodeSanbox Link
Antd's table scroll top on pagination
You can always store pagination in state and compare it to latest one, to avoid scroll of table on changing of anything else in table like filter or sorting.
I hope this would help.
Thanks
Related
I am developing a collapsible list that only shows the first five items and a load more button at first, and when I click the load more button, the full list should be shown. I am using scrollHeight to determine this collapsible list's height and it works fine to show the first five items and the load more button, but after I click the load more button, the height of this collapsible list does not change and the remaining items cannot be displayed due to the height constraint. Does anyone have an idea how to fix it? Thank you so much, I really got stuck here for this whole day.
This is how this collapsible list looks like the collapsible list
This is the code of collapsible list
const Collapsible = ({ showCard, loaded, children }) => {
const collapsibleEl = useRef();
const [scrollHeight, setscrollHeight] = useState();
useEffect(() => {
setscrollHeight(collapsibleEl.current.scrollHeight);
console.log(collapsibleEl.current.scrollHeight);
}, [loaded, showCard]);
return (
<>
<div
className={styles.collapsible}
ref={collapsibleEl}
style={
showCard
? scrollHeight
? { height: `${scrollHeight + 100}px` }
: { height: `${collapsibleEl.current.scrollHeight + 100}px` }
: { height: "0px" }
}
>
{children}
</div>
</>
);
};
export default Collapsible;
I have figured it out, all I need to do is to use settimeout.
like this, just give it a little time to get the scrollheight and then re render.
useEffect(() => {
setTimeout(() => {
setscrollHeight(collapsibleEl.current.scrollHeight);
}, 300);
console.log(collapsibleEl.current.scrollHeight);
}, [showCard, loaded]);
I have a navbar with a list of categories, and I wanted to set the selected category according to what the user is looking at, but for that I need to get the element ID, but these IDs are dynamically set. Currently I already have a function to set the selected category, but it sets the selected category as the click, and I would also like to mark the selected one as the user scrolls.
My code
function onHandleClick(props){
setCurrentCat(props)
document.getElementById(props).scrollIntoView();
}
return (
<div className = {Position ? 'navbarContainer navbarContainerScroll':'navbarContainer'}>
{Categorias.map(item =>(
<ul>
<li className = {item.Cod === currentCat ? 'navbarContainer liSelect' : 'navbarContainer liNormal'}
onClick = {() => onHandleClick(item.Cod)
}>{item.Nome}</li>
</ul>
))}
</div>
)
I currently move the screen to the category are clicked on the navigation bar, how can I set the selected category when the screen focus is on top of it
I have tried to answer your problem as I understand it. I have filled in some extra pieces to help give a full solution. I hope bits and pieces of this are relevant to your issue!
So if I understand you correctly you want to:
be able to automatically update the active tab in your navbar when a user scrolls the page. Also, I assume they are scrolling vertically for my answer.
As per the problem and code you provided, I infer you have a setup somewhat like this:
A Section or Category component containing content for a given item
A Page component that would render a number of Cateogory components and NavBar
Given these two things, I have put the following code together that could help you achieve the functionality you are looking for:
import React, { useEffect, useRef, useState } from "react";
/** Check if an HTML element is within the main focus region of the page */
function isElementInMainFocusArea(
element,
verticalConstrainFactor = 0,
horizontalConstrainFactor = 0
) {
const elementRect = element.getBoundingClientRect();
const documentHeight =
window.innerHeight || document.documentElement.clientHeight;
const documentWidth =
window.innerWidth || document.documentElement.clientWidth;
// Vertical focus region
const topFocusPos = documentHeight * verticalConstrainFactor;
const bottomFocusPos = documentHeight * (1 - verticalConstrainFactor);
// Horizontal focus region
const leftFocusPos = documentWidth * horizontalConstrainFactor;
const rightFocusPos = documentWidth * (1 - horizontalConstrainFactor);
return (
elementRect.top >= topFocusPos &&
elementRect.bottom <= bottomFocusPos &&
elementRect.left >= leftFocusPos &&
elementRect.right <= rightFocusPos
);
}
/** Navigation bar component which will taken in a list of refs.
Each ref must be assigned to or given as a prop to some other section on the page that we want to scroll to. */
function NavBar({ pageSectionRefs, categories }) {
const [currentCat, setCurrentCat] = useState();
/** Set up the scroll event listener to update the currentCat whenever we scroll*/
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
/** Check all the refs we are to watch to see which one of them is in focus */
function handleScroll() {
for (ref in pageSectionRefs.reverse()) {
if (isElementInMainFocusArea(ref.current)) {
setCurrentCat(index);
return; // if two elements are in focus, only the first will be chosen. Could cause a glitch
}
}
}
// Returns what you were previously returning for this component
return (
<div
className={
Position ? "navbarContainer navbarContainerScroll" : "navbarContainer"
}>
{categories.map((item) => (
<ul>
<li
className={
item.Cod === currentCat
? "navbarContainer liSelect"
: "navbarContainer liNormal"
}
onClick={() => onHandleClick(item.Cod)}>
{item.Nome}
</li>
</ul>
))}
</div>
);
}
/** The top level component that will be rendering the NavBar and page sections. */
function MyPage() {
const categories = [];
const pageSectionRefs = categories.map(() => useRef());
return (
<div>
<NavBar pageSectionRefs={pageSectionRefs} categories={categories} />
{categories.map((cat, idx) => {
return (
<div key={idx} ref={pageSectionRefs[idx]}>
Section for category {idx}
</div>
);
})}
</div>
);
}
In case I don't have a full picture of your problem, kindly comment things I may have missed so I update my answer!
References:
The isElementInFocusArea function was adapted from here: How can I tell if a DOM element is visible in the current viewport?
Inspiration for handling list of refs from here: How can I use multiple refs for an array of elements with hooks?
Introduction
I have a FlatList that renders a Tab View in its footer. This Tab View let the user switch between one FlatList or an other. So, these last are sibling FlatLists.
Problem
The first FlatList "A" has a greater height than the second one "B". When I choose the second list, its height is the same as the "A" FlatList's one.
I have reproduced the problem in a snack where you can see a similar code. I recognize that the code is a little long but too simple, just focus only on the parent FlatList (in the App component) and the two FlatLists that are rendered in each tab (at the end of the code)
QUESTION
Any ideas how to solve this issue? I don't know if the problem is in the styles or if I have to do something else to make this work (all flatlists have to have their own height, not the greater).
Thank you, I would really appreciate your help.
UPDATE 2022
const renderScene = ({ route }) => {
//
// 📝 Note: We are hidding tabs in order to avoid the
// "FlexBox Equal Height Columns" typical problem
//
switch (route.key) {
case "bitcoin":
return (
<View style={index !== 0 && styles.hidden}>
<Bitcoin />
</View>
);
case "ethereum":
return (
<View style={index !== 1 && styles.hidden}>
<Etherum />
</View>
);
case "rose":
return (
<View style={index !== 2 && styles.hidden}>
<Rose />
</View>
);
default:
return null;
}
};
...
<TabView
renderTabBar={renderTabBar}
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={handleOnIndexChange}
initialLayout={{ width: layout.width }}
removeClippedSubviews={false}
swipeEnabled
swipeVelocityImpact={0.2}
gestureHandlerProps={{
activeOffsetX: [-30, 30], // To solve swipe problems on Android
}}
style={globalStyles.flexContainer}
/>
Styles:
hidden: { display: "none" }
I have updated the snack with the solution!
As in the snack I implemented my own TabView, I have decided to implement the same solution with the library "react-native-tab-view", as it is the best tab for react native for now.
Think that some people having this issue will be able to solve it.
Basically, what we need to do is to dinamically calculate the height of each tab scene and pass it to the style of the TabView using the onLayout prop.
Just like this:
const renderScene = ({ route }) => {
switch (route.key) {
case "inifiniteScrollFlatList":
return (
<FirstRoute />
);
case "rawDataFlatList":
return (
<View
onLayout={(event) => setTab1Height(event.nativeEvent.layout.height + TAB_HEIGHT)}
>
<SecondRoute />
</View>
);
case "otherRawDataFlatList":
return (
<View
onLayout={(event) => setTab2Height(event.nativeEvent.layout.height + TAB_HEIGHT)}
>
<ThirdRoute />
</View>
);
default:
return null;
}
};
<TabView
style={ index !== 0 && {
height: index === 1 ? tab1Height : tab2Height,
}}
renderTabBar={renderTabBar}
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={setIndex}
initialLayout={initialLayout}
removeClippedSubviews={false} // Pd: Don't enable this on iOS where this is buggy and views don't re-appear.
swipeEnabled={true}
/>
Pd: You shouldn't do this with a tab that uses an infinite scroll with pagination. Instead, you will have to set the height to null to allow the parent FlatList to automatically get its height.
So, I haven't gone through the entire code, nor did I find a solution to your height problem.
But, what you can do is check out React navigation 5 -> createMaterialTopTabNavigator.
It lets you create tabs with separate flatlist for each tab. It will solve the height problem because what is being rendered are separate flatlists as per the active tab. And it will also, make your code much cleaner.
You won't have to use a Flatlist with header and footer components to render the tabs with nested Flatlists.
And if you want to hide the tabs on scroll, that is possible by passing props to the tab navigator that toggle visibility on scroll of the Flatlist using the onScroll event that is called when a Flatlist is scrolled. The same can be done for the visibility of the header as well. And with the proper animations it would look as if the header and the tabs were pushed up on scroll like it does right now.
I ended up removing the tabs content from the tab control altogether. It's hacky but worked for me...
render() {
const {index} = this.state;
return (
<ScrollView>
<TabView
renderPager={this._renderPager}
renderScene={() => null}
onIndexChange={index => this.setState({index})}
initialLayout={{height: 0, width: Dimensions.get('window').width}}
/>
{index === 0 && <Tab1Content />}
{index === 1 && <Tab2Content />}
</ScrollView>
);
Source:- https://github.com/satya164/react-native-tab-view/issues/290#issuecomment-447941998
Given a react-virtualized List with variable content in each row the DOM height needs to be calculated by a rowHeight function - however since that gets called before the row is rendered I am unsure how to actually get the row height.
The examples given for dynamic List row height basically go off a predefined number in the list item's props which doesn't help.
What I think I want to do is render the row on the page at a default height and then get the overflow height on the DOM and set that as the row height. How can I hook into an afterRowRender function or something like that? I imagine performance would suffer so maybe there is a better way of doing this that I am missing.
Check out the docs on CellMeasurer. You can see it in action here.
Basically you'll be looking for something like this:
import React from 'react';
import { CellMeasurer, CellMeasurerCache, Grid } from 'react-virtualized';
const cache = new CellMeasurerCache({
fixedWidth: true,
minHeight: 50,
});
function rowRenderer ({ index, isScrolling, key, parent, style }) {
const source // This comes from your list data
return (
<CellMeasurer
cache={cache}
columnIndex={0}
key={key}
parent={parent}
rowIndex={index}
>
{({ measure }) => (
// 'style' attribute required to position cell (within parent List)
<div style={style}>
// Your content here
</div>
)}
</CellMeasurer>
);
}
function renderList (props) {
return (
<List
{...props}
deferredMeasurementCache={cache}
rowHeight={cache.rowHeight}
rowRenderer={rowRenderer}
/>
);
}
I'm using 'react-virtualized' to render an infinite scrolling list.
However, I am having trouble rendering the rowHeight dynamically. I made an attempt, but it only is relevent for desktop, and feels wrong.
I tried following the examples, but had no success.
What is the correct way to calculate the true row height?
It should be responsive to mobile.
Here is an example:
https://codesandbox.io/s/ADARgvlxB
class App extends React.Component {
render() {
return (
<div>
<AutoSizer>
{({ height, width }) => (
<List
height={600}
width={width}
rowCount={foo.length}
rowHeight={({ index }) => {
const x = foo[index];
if (x.name.length < 10) { return 20; }
else if (x.name.length > 9) { return 40;}
}}
rowRenderer={({ index, style }) => {
const x = foo[index];
return (
<div key={index} style={style}>
{x.name}
</div>
);
}}
/>
)}
</AutoSizer>
</div>
);
}
}
What is the correct way to calculate the true row height?
This is what the react-virtualized CellMeasurer component is for. You can see a demo of it measuring dynamic heights here. The source code for the demo are the *.example.js files here.