diff --git a/README.md b/README.md
index 324d56c1..e2458817 100644
--- a/README.md
+++ b/README.md
@@ -34,6 +34,23 @@ Multiple Select List | Select List
+# What's New in This Fork (changes made for selectList ONLY)
+
+This fork by **FearZaEngineer** is an edit of the original package and introduces key performance optimizations and improvements:
+
+- **Optimized Rendering with FlatList:**
+ Replaces the ScrollView in the dropdown with a FlatList for virtualized rendering. This ensures that only visible items are rendered, improving performance with large data sets.
+- **New Prop: `flatListProps`:**
+ Allows you to pass additional props directly to the underlying FlatList. This gives you full control over performance-related configurations (e.g., `initialNumToRender`, `maxToRenderPerBatch`, `windowSize`, etc.).
+- **Memoized Render Functions:**
+ Uses `useCallback` and `useMemo` to memoize render functions and helper functions, reducing unnecessary re-renders.
+- **Enhanced Search Filtering:**
+ Implements local state for search queries, ensuring smoother and more efficient filtering.
+- **Animation Improvements:**
+ The slide-up/slide-down animations have been optimized to perform better during state changes.
+
+
+
# Compatibility
@@ -48,14 +65,16 @@ Multiple Select List | Select List
# 🔌 Installation
```sh
-$ npm install react-native-dropdown-select-list
+$ npm install react-native-dropdown-select-list@github:FearZaEngineer/react-native-dropdown-select-list#my-custom-selectlist
+
```
OR
```sh
-$ yarn add react-native-dropdown-select-list
+$ yarn add react-native-dropdown-select-list@github:FearZaEngineer/react-native-dropdown-select-list#my-custom-selectlist
+
```
@@ -148,6 +167,8 @@ For Live `Demo` [(Expo Snack)](https://snack.expo.dev/@danish1658/react-native-d
| fontFamily| string | Pass font name to apply globally on each text field of component
| notFoundText| string | Pass your custom message if any search result returns empty
| dropdownShown| boolean | Control your dropdown ( on & off ) state by changing its value to true or false
+| flatListProps| object | NEW : Additional props for item List
+
@@ -264,9 +285,7 @@ const App = () => {
-# 💲 Would you like to support me?
-
-If you would like me come up with similar packages, buy me a cup of coffee to boost my energy.
+# 💲 Would you like to support the creator of the original package?
[](https://paypal.me/danishamindar)
diff --git a/components/SelectList.tsx b/components/SelectList.tsx
index 234a7e10..69a8a6ba 100644
--- a/components/SelectList.tsx
+++ b/components/SelectList.tsx
@@ -1,263 +1,286 @@
-import React from 'react';
+import React, { useCallback, useEffect, useRef, useState, useMemo } from 'react';
import {
- View,
- Text,
- StyleSheet,
- Image,
- TouchableOpacity,
- ScrollView,
- Animated,
- TextInput,
- Keyboard
+ View,
+ Text,
+ StyleSheet,
+ Image,
+ TouchableOpacity,
+ Animated,
+ TextInput,
+ Keyboard,
+ FlatList
} from 'react-native';
import { SelectListProps } from '..';
-type L1Keys = { key?: any; value?: any; disabled?: boolean | undefined }
+type L1Keys = { key?: any; value?: any; disabled?: boolean };
-const SelectList: React.FC = ({
- setSelected,
- placeholder,
- boxStyles,
- inputStyles,
- dropdownStyles,
- dropdownItemStyles,
- dropdownTextStyles,
- maxHeight,
- data,
- defaultOption,
- searchicon = false,
- arrowicon = false,
- closeicon = false,
- search = true,
- searchPlaceholder = "search",
- notFoundText = "No data found",
- disabledItemStyles,
- disabledTextStyles,
- onSelect = () => {},
- save = 'key',
- dropdownShown = false,
- fontFamily
- }) => {
+const SelectList: React.FC = ({
+ setSelected,
+ placeholder,
+ boxStyles,
+ inputStyles,
+ dropdownStyles,
+ dropdownItemStyles,
+ dropdownTextStyles,
+ maxHeight,
+ data,
+ defaultOption,
+ searchicon = false,
+ arrowicon = false,
+ closeicon = false,
+ search = true,
+ searchPlaceholder = "search",
+ notFoundText = "No data found",
+ disabledItemStyles,
+ disabledTextStyles,
+ onSelect = () => {},
+ save = 'key',
+ dropdownShown = false,
+ fontFamily,
+ flatListProps = {}
- const oldOption = React.useRef(null)
- const [_firstRender,_setFirstRender] = React.useState(true);
- const [dropdown, setDropdown] = React.useState(dropdownShown);
- const [selectedval, setSelectedVal] = React.useState("");
- const [height,setHeight] = React.useState(200)
- const animatedvalue = React.useRef(new Animated.Value(0)).current;
- const [filtereddata,setFilteredData] = React.useState(data)
+}) => {
+ const oldOption = useRef(null);
+ const [_firstRender, _setFirstRender] = useState(true);
+ const [dropdown, setDropdown] = useState(dropdownShown);
+ const [selectedVal, setSelectedVal] = useState("");
+ const [height, setHeight] = useState(200);
+ const animatedValue = useRef(new Animated.Value(0)).current;
+ const [filteredData, setFilteredData] = useState(data);
+ const [searchQuery, setSearchQuery] = useState("");
+ const slidedown = useCallback(() => {
+ setDropdown(true);
+ Animated.timing(animatedValue, {
+ toValue: height,
+ duration: 500,
+ useNativeDriver: false,
+ }).start();
+ }, [animatedValue, height]);
- const slidedown = () => {
- setDropdown(true)
- Animated.timing(animatedvalue,{
- toValue:height,
- duration:500,
- useNativeDriver:false,
-
- }).start()
- }
- const slideup = () => {
-
- Animated.timing(animatedvalue,{
- toValue:0,
- duration:500,
- useNativeDriver:false,
-
- }).start(() => setDropdown(false))
- }
-
- React.useEffect( () => {
- if(maxHeight)
- setHeight(maxHeight)
- },[maxHeight])
+ const slideup = useCallback(() => {
+ Animated.timing(animatedValue, {
+ toValue: 0,
+ duration: 500,
+ useNativeDriver: false,
+ }).start(() => setDropdown(false));
+ }, [animatedValue]);
-
- React.useEffect(() => {
- setFilteredData(data);
- },[data])
+ useEffect(() => {
+ if (maxHeight) setHeight(maxHeight);
+ }, [maxHeight]);
+ useEffect(() => {
+ setFilteredData(data);
+ }, [data]);
- React.useEffect(() => {
- if(_firstRender){
- _setFirstRender(false);
- return;
- }
- onSelect()
- },[selectedval])
-
+ // Filter data based on the search query.
+ useEffect(() => {
+ if (searchQuery === "") {
+ setFilteredData(data);
+ } else {
+ const result = data.filter((item: L1Keys) => {
+ const row = item.value.toLowerCase();
+ return row.indexOf(searchQuery.toLowerCase()) > -1;
+ });
+ setFilteredData(result);
+ }
+ }, [searchQuery, data]);
- React.useEffect(() => {
- if(!_firstRender && defaultOption && oldOption.current != defaultOption.key ){
- // oldOption.current != null
- oldOption.current = defaultOption.key
- setSelected(defaultOption.key);
- setSelectedVal(defaultOption.value);
- }
- if(defaultOption && _firstRender && defaultOption.key != undefined){
-
- oldOption.current = defaultOption.key
- setSelected(defaultOption.key);
- setSelectedVal(defaultOption.value);
- }
-
- },[defaultOption])
+ useEffect(() => {
+ if (_firstRender) {
+ _setFirstRender(false);
+ return;
+ }
+ onSelect();
+ }, [selectedVal]);
- React.useEffect(() => {
- if(!_firstRender){
- if(dropdownShown)
- slidedown();
- else
- slideup();
-
- }
-
- },[dropdownShown])
+ useEffect(() => {
+ if (!_firstRender && defaultOption && oldOption.current !== defaultOption.key) {
+ oldOption.current = defaultOption.key;
+ setSelected(defaultOption.key);
+ setSelectedVal(defaultOption.value);
+ }
+ if (defaultOption && _firstRender && defaultOption.key !== undefined) {
+ oldOption.current = defaultOption.key;
+ setSelected(defaultOption.key);
+ setSelectedVal(defaultOption.value);
+ }
+ }, [defaultOption]);
+ useEffect(() => {
+ if (!_firstRender) {
+ if (dropdownShown) slidedown();
+ else slideup();
+ }
+ }, [dropdownShown, _firstRender, slidedown, slideup]);
+ const handleSelectItem = useCallback((item: L1Keys) => {
+ const key = item.key ?? item.value ?? item;
+ const value = item.value ?? item;
+ if (save === 'value') {
+ setSelected(value);
+ } else {
+ setSelected(key);
+ }
+ setSelectedVal(value);
+ slideup();
+ setTimeout(() => {
+ setFilteredData(data);
+ setSearchQuery("");
+ }, 800);
+ }, [data, save, slideup, setSelected]);
- return(
-
- {
- (dropdown && search)
- ?
-
-
- {
- (!searchicon)
- ?
-
- :
- searchicon
- }
-
- {
- let result = data.filter((item: L1Keys) => {
- val.toLowerCase();
- let row = item.value.toLowerCase()
- return row.search(val.toLowerCase()) > -1;
- });
- setFilteredData(result)
- }}
- style={[{padding:0,height:20,flex:1,fontFamily},inputStyles]}
- />
- slideup()} >
+ const renderItem = useCallback(({ item }: { item: L1Keys; index: number }) => {
+ const key = item.key ?? item.value ?? item;
+ const value = item.value ?? item;
+ const disabled = item.disabled ?? false;
+ if (disabled) {
+ return (
+ {}}
+ >
+
+ {value}
+
+
+ );
+ }
+ return (
+ handleSelectItem(item)}
+ >
+ {value}
+
+ );
+ }, [disabledItemStyles, disabledTextStyles, dropdownItemStyles, dropdownTextStyles, fontFamily, handleSelectItem]);
- {
- (!closeicon)
- ?
-
- :
- closeicon
- }
-
-
-
-
-
-
-
- :
- { if(!dropdown){ Keyboard.dismiss(); slidedown() }else{ slideup() } }}>
- { (selectedval == "") ? (placeholder) ? placeholder : 'Select option' : selectedval }
- {
- (!arrowicon)
- ?
-
- :
- arrowicon
- }
-
-
- }
-
- {
- (dropdown)
- ?
-
-
+ const keyExtractor = useCallback((item: L1Keys, index: number) => {
+ return item.key ? String(item.key) : String(index);
+ }, []);
- {
- (filtereddata.length >= 1)
- ?
- filtereddata.map((item: L1Keys,index: number) => {
- let key = item.key ?? item.value ?? item;
- let value = item.value ?? item;
- let disabled = item.disabled ?? false;
- if(disabled){
- return(
- {}}>
- {value}
-
- )
- }else{
- return(
- {
- if(save === 'value'){
- setSelected(value);
- }else{
- setSelected(key)
- }
-
- setSelectedVal(value)
- slideup()
- setTimeout(() => {setFilteredData(data)}, 800)
-
- }}>
- {value}
-
- )
- }
-
- })
- :
- {
- setSelected(undefined)
- setSelectedVal("")
- slideup()
- setTimeout(() => setFilteredData(data), 800)
-
- }}>
- {notFoundText}
-
- }
-
-
-
-
-
- :
- null
- }
-
-
+ return (
+
+ {dropdown && search ? (
+
+
+ { !searchicon ? (
+
+ ) : searchicon }
+ setSearchQuery(val)}
+ value={searchQuery}
+ style={[{ padding: 0, height: 20, flex: 1, fontFamily }, inputStyles]}
+ />
+
+ { !closeicon ? (
+
+ ) : closeicon }
+
+
- )
-}
+ ) : (
+ {
+ if (!dropdown) {
+ Keyboard.dismiss();
+ slidedown();
+ } else {
+ slideup();
+ }
+ }}
+ >
+
+ {selectedVal === "" ? (placeholder ? placeholder : 'Select option') : selectedVal}
+
+ { !arrowicon ? (
+
+ ) : arrowicon }
+
+ )}
+ {dropdown && (
+
+
+ {filteredData.length === 0 && (
+ {
+ setSelected(undefined);
+ setSelectedVal("");
+ slideup();
+ setTimeout(() => {
+ setFilteredData(data);
+ setSearchQuery("");
+ }, 800);
+ }}
+ >
+ {notFoundText}
+
+ )}
+
+ )}
+
+ );
+};
export default SelectList;
-
const styles = StyleSheet.create({
- wrapper:{ borderWidth:1,borderRadius:10,borderColor:'gray',paddingHorizontal:20,paddingVertical:12,flexDirection:'row',justifyContent:'space-between' },
- dropdown:{ borderWidth:1,borderRadius:10,borderColor:'gray',marginTop:10,overflow:'hidden'},
- option:{ paddingHorizontal:20,paddingVertical:8,overflow:'hidden' },
- disabledoption:{ paddingHorizontal:20,paddingVertical:8,flexDirection:'row',alignItems:'center', backgroundColor:'whitesmoke',opacity:0.9}
-
-})
+ wrapper: {
+ borderWidth: 1,
+ borderRadius: 10,
+ borderColor: 'gray',
+ paddingHorizontal: 20,
+ paddingVertical: 12,
+ flexDirection: 'row',
+ justifyContent: 'space-between'
+ },
+ dropdown: {
+ borderWidth: 1,
+ borderRadius: 10,
+ borderColor: 'gray',
+ marginTop: 10,
+ overflow: 'hidden'
+ },
+ option: {
+ paddingHorizontal: 20,
+ paddingVertical: 8,
+ overflow: 'hidden'
+ },
+ disabledoption: {
+ paddingHorizontal: 20,
+ paddingVertical: 8,
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: 'whitesmoke',
+ opacity: 0.9
+ }
+});