How to implement this lib in a Custom Flatlist - react-native-popup-menu

i have a flatlist like image bellow. The code is this.
How to implement the pop menu in this case?
renderList = () => (
<FlatList
data={this.props.contracts.data}
keyExtractor={item => String(item.id)}
renderItem={({ item }) => <ListItem onPress={() => {}} listItem={item} />}
/>
);

There is nothing special about rendering popup menu inside of flat list. Simply put it into your ListItem component.
Ad "in most cases you should not have more menu providers in your app (see API documentation). In other cases use skipinstacecheck prop" warning. Normally (like 98% of cases) you should not have multiple MenuProviders in your application. If you put it inside of ListItem, it will be rendered multiple times. Just use one MenuProvider on the top of your applications - see main README:
Wrap your application inside MenuProvider and then simply use Menu
component where you need it.
And there are plenty of examples where you can look into, e.g. https://github.com/instea/react-native-popup-menu/blob/master/examples/InFlatListExample.js

Related

Swipe to next screen (infinite)

I have a calendar section in my app where I want to be able to swipe right or left to go to the next or previous day.
I know that you can use createMaterialTopTabNavigator from React Navigation to do something similar, but I'm not sure if it would work in this specific scenario (where I would have an infinite number of screens and wouldn't be able to predefine them).
I also considered using react-native-gesture-handler's Swipeable component to navigate to the next/previous day screen on a left/right swipe but I'm not sure if this is the easiest/best way to approach this problem.
As you mentioned, you can use Tabs or Swipable. There are some other options like using <ifaram> or <WebView> and using a web URL instead of RN components but it's can be tricky and hard to manipulate.
As a simple solution, you can use carousels instead of using multi screen defining navigation. It's very simple. assume that your screens are an image in an image gallery and you can swipe left/right.
There are many libraries, one of the best ones is: react-native-snap-carousle
Take a look at it's example:
import Carousel from 'react-native-snap-carousel';
export class MyCarousel extends Component {
_renderItem = ({item, index}) => {
return (
<View style={styles.slide}>
<Text style={styles.title}>{ item.title }</Text>
</View>
);
}
render () {
return (
<Carousel
ref={(c) => { this._carousel = c; }}
data={this.state.entries}
renderItem={this._renderItem}
sliderWidth={sliderWidth}
itemWidth={itemWidth}
/>
);
}
}
So you can pass a screen/page as _renderItem to the Carousel

ReactNative: SectionList SectionHeaders overwriting ListFooter

I have a React Native page that contains the core component SectionList. The SectionList has sticky section headers (stickySectionHeadersEnabled) and a list footer (ListFooterComponent). As the user scrolls past the last section, the final section header remains stuck to the top of the page overwriting the footer. However I would prefer the sticky headers to be contained within the body of the section list area and not remain on screen beyond the end of the last section.
Is it possible to achieve this with SectionList or should I take another approach?
Expo snack demonstrating this behaviour (iOS & Android only)
https://snack.expo.io/#unstableair/rn-sectionlist-footer-overlay-example
<SectionList
sections={DATA}
keyExtractor={(item, index) => item + index}
renderItem={({ item }) => (<View style={styles.item}><Text style={styles.title}>{item}</Text></View>)}
renderSectionHeader={({ section: { title } }) => (<Text style={styles.header}>{title}</Text>)}
stickySectionHeadersEnabled={true}
ListFooterComponent={<View style={styles.footer}><Text>ListFooterComponent </Text></View>}
/>
To work around this problem, I added an empty section to the bottom of the SectionList data. The last SectionHeader still overwrites the ListFooter but because it's a View with 0 height you can't see it.

How to make a flat list scroll Infinitely in React Native With a Finite Amount of data in Array

I have flat list horizontally set
with data of 11 items coming from an array, which is fixed and never changes
what I want is when user reaches at the end of flat list while scrolling, the data should remain the same but the first item should
show up in the last and then so on
here is what I have tried so far
<FlatList
{...this.props}
ref={ref => {
this.infListRef = ref;
}}
data={this.props.data}
onScrollEndDrag={this.handleScroll}
initialScrollIndex={0}
scrollEventThrottle={16}
renderItem={this.props.renderItem}
onScroll={({nativeEvent}) => this.checkScroll(nativeEvent)}
horizontal
showsHorizontalScrollIndicator={false}
keyExtractor={item => item.id}
/>
Any help will be highly appreciated.
Basically, implementing onScroll usage is when you want to be noticed when the actually scroll related to the scroll position (aminations for instance). When you would like to be notified when the user reaches, or about to reach, to the end of the FlatList.
You should implement onEndReached and onEndReachedThreshold to handle a better user experience when the user reaches the threshold.
The new data you're getting from the source (server or no matter wherefrom) should be concatenated to existing this.props.data
See good blog post - https://scotch.io/tutorials/implementing-an-infinite-scroll-list-in-react-native
And this SO answers - React Native Infinite Scroll
My solution refers to pagination because infinite scroll is a private case of pagination, it's the exact same approach.
If you want image or video list
One other approach which is kind a hack and an easy one is using react-native-snap-carousel
<Carousel
ref={ (c) => { this._carousel = c; } }
data={this.state.data}
renderItem={this._renderItem.bind(this)}
onSnapToItem={this.handleSnapToItem.bind(this)}
sliderWidth={360}
itemWidth={256}
layout={'default'}
firstItem={0}
itemHeight={20}
sliderHeight={20}
loop
vertical
loopClonesPerSide={100}
/>
Example:
https://snack.expo.io/#kurtesy/react-native-snap-carousel-example
You can achieve this using onEndReached method of Flatlist.
This is the idea behind answer.
state = {
data: [] //your initial data
}
<Flatlist
{…this.props}
extraData={this.state}
onEndReached = {() => {
this.setState((prevState) =>{
data: […prevState,this.state.data]
)}}
/>

How do I implement Algolia Search filtering in a React Native Modal component?

I am using Algolia search in my React Native app, following the instructions in guides/building-search-ui/going-further/native/react
I have created a RefinementList as per the instructions, and this works fine when placed directly with the app, as per
<InstantSearch
searchClient={searchClient}
indexName={THE_INDEX}
root={root}
>
<RefinementList attribute="brand.name" />
<SearchBox />
<InfiniteHits />
</InstantSearch>
When this runs and I enter a search term I happily get a list of my faceted brand names. But I need this to work within a modal. So following Algolia's instructions I have created a Filters component and use my RefinementList from within that instead:
<InstantSearch
searchClient={searchClient}
indexName={THE_INDEX}
root={root}
searchState={this.state.searchState}
onSearchStateChange={this.onSearchStateChange}
>
<Filters
isModalOpen={this.state.isModalOpen}
toggleModal={this.toggleModal}
indexName={THE_INDEX}
searchClient={searchClient}
searchState={this.state.searchState}
onSearchStateChange={this.onSearchStateChange}
/>
<SearchBox />
<FilterButton
onFilter={this.toggleModal}
/>
<InfiniteHits />
</InstantSearch>
However the modal is always empty. The console shows that when the RefinementList is simply a child of the InstantSearch then its items array gets populated, but when the RefinementList is invoked within the Filters component then it's empty. The Filters component is exactly as per Algolia's docs, apart from the fact I pass in the indexName as a prop. I've checked in the React Native debugger and the RefinementList has access to the same context, the searchState is being set, and onSearchStateChange is being invoked correctly. The indexName is correct.
What am I doing wrong?
To fix this I had to add a 'virtual' SearchBox, ala
const VirtualSearchBox = connectSearchBox(() => null)
which is used as a child of the InstantSearch component in the Filters component, making Filters more like
const Filters = ({
isModalOpen,
searchState,
searchClient,
toggleModal,
onSearchStateChange,
indexName
}) => (
<Modal animationType="slide" visible={isModalOpen}>
<SafeAreaView>
<InstantSearch
searchClient={searchClient}
indexName={indexName}
searchState={searchState}
onSearchStateChange={onSearchStateChange}
>
<VirtualSearchBox />
<RefinementList attribute="brand" />
<TouchableOpacity style={styles.closeButton} onPress={toggleModal}>
<Text style={styles.closeButtonText}>Close</Text>
</TouchableOpacity>
</InstantSearch>
</SafeAreaView>
</Modal>
)
Inside the modal the searchState is always falsy because the SearchBox is not mounted.
Each time a request happens inside the modal the emtpy state will be provided.
The refinements inside the searchState are not enough to apply a refinement on the search parameters. All of the widgets associated with the refinement have to be mounted (ref: Search State docs).

Logical approach to navigation and flatlist

I click on a button on one screen which loads another screen with a flat list which renders many rows. My conundrum is that I hang on the first screen while the flatlist processes.
My best effort so far is a loader, hidden this.props.children to process the flatlist, then hide the loader and show this.props.children again.
I'm sure there must be a more logical approach?
Ta,
Chris
first instead ho hiding flatlist and showing loader you can use
Refresh Control from React-native. which will we do the same same job
with ease.
second if your list is long you can lazy load your data by using onEndReached Callback this will decrease the loading time .
third make your renderComponent in flatlist a pure Component .which will stop unecessary refreshes and increase performance.
check the code below .....
<FlatList
data={this.props.questions}
renderItem={({ item, index }) => <QuestionCard //your pure component
item={item}
index={index}
onPress={this.openQuestionDetail}
/>
}
ref={'flatlist'}
refreshControl={
<RefreshControl //imported from react-native
refreshing={isFetching} //used to show loader while loading
onRefresh={this.fetchQuestions}
title="Pull to refresh"
tintColor="#fff"
titleColor="#fff"
colors={[Colors.secondary_button]}
/>
}
onEndReached={this.handleDynamicLoading} //callback for lazyloading
onEndReachedThreshold={0.5}
keyExtractor={(item, index) => item.qid}
/>
hope this helps... :)