I'm trying to hide selected item while it's exist in compared Array, but for some reason when I have two Strings that are same on array it's hiding both items, any solution for that?
Array example:
["I'm", "going", "to", "go" ,"to", "London"]
/Get selected value
const handleSelected = (e) => {
setReceivedItems(e);
};
//Update selected data at first render
useEffect(() => {
setNewItems((newItem) => [...newItem, receivedItems]);
}, [receivedItems]);
const deleteWord = (receivedItem) => {
setNewItems((data) => data.filter((item) => item !== receivedItem));
};
Return (
<View
style={{
...
}}
key={i}
>
{enItems.enWordR?.map((enWordR, i) => (
<TouchableOpacity
key={i}
onPress={handleSelected.bind(this, enWordR)}
style={[
newItems.find((item) => item === enWordR) <---- item get hidden with this method
? styles.hideItem
: styles.showItem,
]}
>
<Button
title={enWordR}
/>
</TouchableOpacity>
))}
</View>
>
)
So, in above example both "to" will be hidden
So into the cartscreen, I am importing a dropdown component.
Now, there is a different dropdown inside the cartscreen called renderDropdown, and I'm using it to display two different data lists as two dropdowns for the user to choose from. Although this renderDropdown is functioning properly, selecting an imported dropdown causes the selected value in my renderDropdown to be cleared from the dropdown bar.
I verified that renderDropdown's value remains in the current state and I noticed that when I click on this imported drop-down, I get a message printed to the console(I have added console.log in cart screen whenever screen renders), which indicates that my entire screen is rendering. Could someone please look into this and let me know what's wrong?
Here is the code for a dropdown menu.
[I've also used the same component in a lot of other screens, and it works just fine]
import { StyleSheet, View } from 'react-native'
import React from 'react'
import { Dropdown} from 'react-native-element-dropdown'
import { COLORS } from '../constants'
const DropdownComponent = ({text, extractorValue, external_Id, data:mainData, extraData, value, setValue, isFocus, setIsFocus,area=false, retailer=false, retailerC=false, extraStyling}) => {
return (
<View style={[styles.container, {...extraStyling}]}>
<Dropdown
style={[styles.dropdown, isFocus && { borderColor: COLORS.blue90 }]}
placeholderStyle={styles.placeholderStyle}
selectedTextStyle={styles.selectedTextStyle}
inputSearchStyle={styles.inputSearchStyle}
iconStyle={styles.iconStyle}
data={mainData}
containerStyle={{
backgroundColor:COLORS.white10,
borderRadius:10,
marginTop:10,
borderColor:COLORS.gray10,
shadowColor:COLORS.blue90,
shadowOffset:{
height:15,
width: 15
},
elevation:19,
}}
search
maxHeight={300}
labelField={extractorValue ? extractorValue :"name"}
valueField={external_Id ? external_Id :"name"}
placeholder={!isFocus ? `Select ${text ? text : 'Item'}` : '...'}
searchPlaceholder="Search..."
value={value}
onFocus={() => setIsFocus(true)}
onBlur={() => setIsFocus(false)}
onChange={item => {
retailer ?
retailerC ?
(
setValue({...extraData, retailerClass:external_Id ? item[external_Id] : item.name})
):
(
( area ?
setValue({...extraData, area:external_Id ? item[external_Id] : item.name})
:
setValue({...extraData, route:external_Id ? item[external_Id] : item.name})
)
)
:
(
setValue(external_Id ? item[external_Id] : item.name)
)
setIsFocus(false)
}}
/>
</View>
)
}
export default DropdownComponent
and here is the cartScreen code which is causing trouble , also i want to include that i have to show 3 dropdowns on the screen so i was using the same component renderDropdown for all of them but i was having the same issue so i though it is because of third dropwdown (namely value scheme ) so i used external one but having the same issue.
const CartDetailsScreen = ({navigation}) => {
const [loading, setLoading] = React.useState(false)
const {cartItems, setCartItems } = useContext(mapContext)
const { createOrders, createOrderStatus, distributors, setDistributors, getDistributors, schemes, setSchemes, getSchemes} = useContext(commonUrlsContext)
useLayoutEffect(()=>{
navigation.setOptions({
headerShown:true,
headerTitle:'CART DETAILS',
...HeaderStyles,
headerLeft: () =>(
<HeaderLeft navigation={navigation} />
)
})
},[])
const [valueSchemeFromDropDown, setValueSchemeFromDropDown] = React.useState('')
React.useEffect(()=>{
getSchemes()
getDistributors()
return () =>{
setDistributors([])
setSchemes([])
}
},[])
React.useEffect(()=>{
if(createOrderStatus){
ToastAndroid.show('Order created successfully', ToastAndroid.CENTER)
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [
{ name: 'OrderSuccessful' },
],
})
);
setTimeout(()=>{{navigation.navigate('OrderSuccessful'), setCartItems([])}},1000)
}
},[createOrderStatus])
function RenderDropDown({index, text, data, external_Id, extractorValue, width, qtyScheme, valueScheme}){
return(
<View style={[styles.container, width && {width: width}]}>
<Dropdown
style={[styles.dropdown]}
placeholderStyle={styles.placeholderStyle}
selectedTextStyle={styles.selectedTextStyle}
inputSearchStyle={styles.inputSearchStyle}
iconStyle={styles.iconStyle}
data={data}
containerStyle={{
borderRadius:10,
marginTop:10,
borderColor:COLORS.gray10,
shadowColor:COLORS.gray90,
shadowOffset:{
height:10,
width: 10
},
elevation:15,
}}
search
maxHeight={300}
labelField={extractorValue ? extractorValue :"name"}
valueField={external_Id ? external_Id :"name"}
placeholder={`Select ${text ? text : 'item'}`}
searchPlaceholder="Search..."
// value={qtyScheme ? cartItems[index]?.distributorName}
onChange={item => {
qtyScheme ?
(
console.log(1),
cartItems[index].qtyScheme = item[external_Id],
setCartItems(cartItems)
)
:
(
console.log(2),
cartItems[index].distributorName = item[extractorValue],
cartItems[index].distributorId = item[external_Id],
setCartItems(cartItems)
)
}}
/>
</View>
)
}
const removeFromCart = (id) =>{
let updatedCart = cartItems.filter(product => product?.products?.Id !== id)
setCartItems(updatedCart)
ToastAndroid.show('Item Removed From the Cart.', ToastAndroid.SHORT)
if(updatedCart.length === 0){
navigation.goBack()
}
}
const submitHandler = () =>{
setLoading(true)
createOrders(cartItems, valueSchemeFromDropDown)
}
const reduceHandler = (item, index) =>{
if(item.qty === 1){
let newResults = cartItems.filter(product => product.products.Id !== item.products.Id)
setCartItems(newResults)
if(newResults.length === 0){
navigation.goBack()
}
}
else{
item.qty = item.qty - 1
let newResults = cartItems.filter(product => product.products.Id !== item.products.Id ? product : item)
setCartItems(newResults)
}
}
const [testValue, setTestValue] = React.useState('')
const [testFocus, setTestFocus] = React.useState(false)
const incrementHandler = (item, index) =>{
let newResults = cartItems.map(product =>
product.products.Id === item.products.Id ? {...item, qty: product.qty + 1} : product)
setCartItems(newResults)
}
return (
<>
{ loading ?
<RowCenter style={{flex:1, flexDirection: 'column', alignItems:'center'}}>
<StyledText fontSize={'20px'}>{createOrderStatus ? 'Redirecting..' : 'Loading..'}</StyledText>
</RowCenter> :
<>
<View style={{flex:0.8}}>
<ScrollView showsVerticalScrollIndicator={false}>
{cartItems?.map((item, index)=>{
return(
<View key={item?.products?.Id} style={{flexDirection:'row', padding:13, borderRadius:10, margin:10, alignItems:'center', backgroundColor:COLORS.green20, ...customShadow }}>
<View style={{width:'100%'}}>
<StyledText>Product Name : {item?.products?.Name}</StyledText>
<ExtraSpace />
{item?.products?.Description &&
<StyledText>Product Description : {item?.products?.Description?.length > 30 ? item?.products?.Description?.slice(0,30) + '...': item?.products?.Description }</StyledText>
}
<ExtraSpace />
<View style={{flexDirection:'row', justifyContent:'space-between', alignItems:'center', padding:10}}>
<TouchableOpacity onPress={()=>removeFromCart(item?.products?.Id)} style={{flexDirection:'row', justifyContent:'center', alignItems:'center'}}>
<SimpleLineIcons name="trash" size={15} color={COLORS.error} />
<StyledText color={COLORS.error}>Remove</StyledText>
</TouchableOpacity>
<View style={{width:'40%', flexDirection:'row', justifyContent:'space-between', alignItems:'center',}}>
<TouchableOpacity onPress={()=>reduceHandler(item, index)}>
<Feather name="minus-circle" size={22} color={COLORS.gray90} />
</TouchableOpacity>
<StyledText>Qty : {item?.qty}</StyledText>
<TouchableOpacity onPress={()=>incrementHandler(item, index)} >
<Feather name="plus-circle" size={22} color={COLORS.gray90} />
</TouchableOpacity>
</View>
</View>
<RenderDropDown index={index} text={'Distributor'} data={distributors?.response} external_Id='external_Id' extractorValue='name' />
{item.distributorName &&
<Label color={'#131821'}> Clone Selected : {item.distributorName}</Label>
}
<RenderDropDown id={item?.products?.id} index={index} text={'Quantity Scheme'} data={schemes?.response?.filter(scheme => scheme.Type__c === 'Quantity Scheme')} external_Id='Id' extractorValue='Name' qtyScheme={true}/>
</View>
</View>
)
})}
</ScrollView>
</View>
<View style={{flex:0.2, justifyContent:'center', alignItems:'center', borderWidth:1, borderTopLeftRadius:10, borderTopRightRadius:10, marginBottom:2, marginHorizontal:1, borderTopColor:'gray', backgroundColor:"transparent"}}>
<DropdownComponent text={'Value Scheme'} data={schemes?.response?.filter(scheme => scheme.Type__c === 'Value Scheme')} external_Id='Id' extractorValue={'Name'} value={testValue} setValue={setTestValue} isFocus={testFocus} setIsFocus={setTestFocus} extraStyling={{width: '100%', marginTop:10, marginBottom:1}}/>
{/* <RenderDropDown text={'Value Scheme'} data={valueScheme} external_Id='Id' extractorValue='Name' valueScheme={true}/> */}
<TextButton onPress={()=>{cartItems?.length === 0 ? null : submitHandler()}} componentStyling={{width:'94%', padding:8, marginHorizontal:10, marginBottom:10, marginTop:1}} title='Place Order'/>
</View>
</>
}
</>
)
}
Hey you have added these
onFocus={() => setIsFocus(true)}
onBlur={() => setIsFocus(false)}
and these are setStates , so it will re render when dropdwon opens or closes
Hope it helps. feel free for doubts
I use memo in my script. I dont know why my data rerenders when I use fast-compare (isEqual) and when I use my own function (isEq) then its not rerender. Why ?
import isEqual from 'react-fast-compare'
function isEq(prev: IColorItem, next: IColorItem) {
if(prev.activeColor === next.activeColor) {
return true;
}
}
// rerenders
const Item = memo(({ color, index, style, activeColor, onPress }: IColorItem) => {
console.log('render');
return (
<Button style={s.center} onPress={() => onPress(color)}>
<Text>{color}</Text>
</Button>
)
// #ts-ignore
}, isEqual);
// No rerender
const Item = memo(({ color, index, style, activeColor, onPress }: IColorItem) => {
console.log('render');
return (
<Button style={s.center} onPress={() => onPress(color)}>
<Text>{color}</Text>
</Button>
)
// #ts-ignore
}, isEq);
€:
Item:
const renderItem: ListRenderItem<ColorsType> = ({ item, index }) => (
<Item
color={item}
index={index}
style={style}
activeColor={activeColor}
onPress={onPress}
/>
)
I am using scrollTo to let scrollview element scroll to a particular id as follows:
let scrollviewRef = useRef();
useEffect(() => {
selectedid && selectedid!=null && selectedid!=undefined &&
scrollviewRef.current?.scrollTo({
y:selectedid,
animated:true,
})
getData();
BackHandler.addEventListener('hardwareBackPress', handleBackButtonOnnclick);
return () => {
BackHandler.removeEventListener(
'hardwareBackPress',
handleBackButtonOnnclick,
);
};
}, [changedstatus]);
<ScrollView ref={scrollviewRef}>
{data != '' &&
data !== undefined &&
data !== null &&
data.map((item) => {
const selected = item.vaccine_list
.map((a) => a.vaccineInternalId)
.includes(selectedid);
return (
<TouchableOpacity
key={item.id}
style={{
paddingLeft: 10,
paddingRight: 10,
}}
onPress={() => handleOnPress(item.id, item)}>
{expand[item.id] ? (
<ExpandedVaccineComponent
item={item}
id={id}
navigation={navigation}
changevaccinestatus={changevaccinestatus}
childdob={childdob}
/>
) : (
<NotExpandedVaccineComponent item={item} />
)}
</TouchableOpacity>
);
})}
</ScrollView>
But when I execute this, it is not initially scrolling to the selectedid, could anyone tell me what have I missed out here?
Any leads would be great.
Let me know if anything else is required for better clarity.
I would like to add a searchbar in my header. I am using react-navigation, and want to create an effect like in the below 2 pictures. When you press the search icon, the hamburger icon becomes a arrow-back icon, the header title becomes a search field. I have tried to accomplish this with the navigationOptions but the problem is that it is static and it cannot be updated when an action happens on the header itself. So for experimenting what I want to accomplish is that when the search icon is pressed, the hamburger icon becomes a arrow-back icon. Thank you!
var search = false;
const menuButton = navData => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Menu"
iconName="ios-menu"
onPress={() => {
navData.navigation.toggleDrawer();
}}
/>
</HeaderButtons>
);
const goBackButton = navData => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Menu"
iconName="ios-arrow-back"
onPress={() => {
search=false
}}
/>
</HeaderButtons>
);
MyScreen.navigationOptions = navData => {
return {
headerTitle: 'My title',
headerLeft: search ? goBackButton : menuButton(navData),
headerRight: (
<BorderlessButton
onPress={() => search=true}
style={{ marginRight: 15 }}>
<Ionicons
name="md-search"
size={Platform.OS === 'ios' ? 22 : 25}
/>
</BorderlessButton>
)
}
};
try use state bro !
constructor(props) {
super(props);
this.state = {
search:false
}
}
const menuButton = navData => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Menu"
iconName="ios-menu"
onPress={() => {
navData.navigation.toggleDrawer();
}}
/>
</HeaderButtons>
);
const goBackButton = navData => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Menu"
iconName="ios-arrow-back"
onPress={() => {this.setState({search:false})}}
/>
</HeaderButtons>
);
MyScreen.navigationOptions = navData => {
return {
headerTitle: 'My title',
headerLeft: this.state.search ? goBackButton : menuButton(navData),
headerRight: (
<BorderlessButton
onPress={() => {this.setState({search:true})}}
style={{ marginRight: 15 }}>
<Ionicons
name="md-search"
size={Platform.OS === 'ios' ? 22 : 25}
/>
</BorderlessButton>
)
}
};
I have fixed it by passing information to my navigationOptions with setParams and getParam. The only problem I faced was in infinite loop which I could solve with the proper use of useEffect and useCallback.
const MyScreen = props => {
const dispatch = useDispatch();
var search = useSelector(state => state.verbs.search);
useEffect(() => {
props.navigation.setParams({search: search});
}, [search]);
const toggleSearchHandler = useCallback(() => {
dispatch(toggleSearch());
}, [dispatch]);
useEffect(() => {
props.navigation.setParams({toggleSearch: toggleSearchHandler});
}, [toggleSearchHandler]);
return (<View> ...
</View>
);
};
MyScreen.navigationOptions = navData => {
const toggleSearch = navData.navigation.getParam('toggleSearch')
return {
headerTitle: 'Verbs',
headerLeft: navData.navigation.getParam('search') ? gobackButton : menuButton(navData),
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Menu"
iconName="ios-star"
onPress={toggleSearch}
/>
</HeaderButtons>
)
}
};