Hey guys Im making a custom size picker I want to select single size at a time but onPress all item got changed..
my onPress event
onPressItemSize = (item,index:string) => {
this.setState((item) => {
const xl =
xl == item ? this.setState({xl:true}) : this.setState({xl:false});
return { xl };
});
this.setState({selectedSize:item.value})
};
and this is my flatlist component
<FlatList
data={this.state.label}
numColumns={5}
keyExtractor={(item, index) => index.toString()}
extraData={this.state}
renderItem={({item,index}) =>
<View style={{padding:10,}}>
<TouchableOpacity
onPress={this.onPressItemSize.bind(this, item,index)}
style={[styles.Buttoncolor,this.state.xl?null:styles.onfocusbutton]}>
<Text adjustsFontSizeToFit
textTransform='uppercase'
style={[styles.textcolor,this.state.xl?null:styles.white]}>
{item.label}
</Text>
</TouchableOpacity>
</View>
}
/>
Im not sure which state are you trying to set but you need to keen in mind that calling setState will trigger an async function and you need to wait until the new state is successfully changed. i would also use arrow functions for not binding the functions when calling them.
onPressItemSize = (item, index) => {
const { xl } = this.state; //what is xl ?? im assuming it is in your state
const callback = () => {console.log("State changed");}
var newXL = false;
if(xl === item){
newXL = true
}
//you can set diferents values at the same time
this.setState({xl: newXL, selectedSize: item.value }, callback)
};
<FlatList
data={this.state.label}
numColumns={5}
keyExtractor={(item, index) => index.toString()}
extraData={this.state}
renderItem={({item, index}) =>
<View style={{padding:10,}}>
<TouchableOpacity
onPress={() => onPressItemSize(item, index)} //changed
style={[styles.Buttoncolor,this.state.xl?null:styles.onfocusbutton]}>
<Text adjustsFontSizeToFit
textTransform='uppercase'
style={[styles.textcolor,this.state.xl?null:styles.white]}>
{item.label}
</Text>
</TouchableOpacity>
</View>
}
/>
Related
I have a flatlist that is receiving a friendsArray with the following data structure...
I have a modal that has an onPress function, with that onPress i'd like to get the value of this key. I have the following Code, but usually this code provides me with the key of whatever i just selected in the flatlist... i'd like to get the key of the item selected one level deeper, how do i do this?
Here is App.js
onFriendChatPress = key => {
let friend = this.state.friendsArray.find(game => { return game.key === key })
}
render(){
return{
<View>
<FriendsModal
onChatPress={() => this.onChatPress()}
onClosePress={() => this.closeModal()}
onFriendPress={() => this.onFriendPress()}
onFriendChatPress={() => this.onFriendChatPress()}
selGame={this.state.selGame}
visible={this.state.modalVisible}
selGame={this.state.selGame}
/>
</View>
}
Here is FlatList in the FriendsModal
<FlatList
style={styles.flatList}
data={this.props.selGame.friends}
horizontal={true}
renderItem={(info) => (
<ModalProfileCard
displayName={info.item.displayName}
image={info.item.image}
onFriendPress={() => this.props.onFriendPress(info.item.key)}
onFriendChatPress={() => this.props.onFriendChatPress(info.item.key)}
/>
)
}
/>
Here is the Card in the modal
function modalProfileCard(props) {
return (
<View style={styles.container}>
<TouchableOpacity onPress={props.onFriendsPress} style={styles.friendInfo}>
<Image style={styles.profImage} source={{ uri: props.image }} />
<View style={styles.nameContainer}>
<Text style={styles.name}>{props.displayName}</Text>
</View>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={props.onFriendChatPress}>
{buttonText}
</TouchableOpacity>
</View >
)
}
You can do something like this.
const onPress = (key) => {
//you have the key here
}
return (
<Flatlist
data={your_data}
renderItem={({item})=> <YourComponent {...item} onPress={onPress} />}
/> )
const YourComponent = ({key,onPress}) => {
const onPress = () => {
onPress(key);
}
return (
<TouchableOpacity onPress={onPress}>
</TouchableOpacity>
)
}
Though I understand is
In renderItem, shouldn't you use info.displayName instead of info.item.displayNam? and so on ..
There is also a parent FlatList? You are saving the selected game in state as selGame right? You can save it's index also and can pass to child component so It would be easy to find the selected game's key.
I need to set the state to detect which item in the current viewport is visible. for this purpose, I write below code:
const [inViewPort, setInViewPort] = useState(0);
const viewabilityConfig = {
viewAreaCoveragePercentThreshold: 30,
};
const onViewableItemsChanged = ({viewableItems, changed}) => {
if (changed && changed.length > 0) {
setInViewPort(changed[0].index);
}
};
return (
<SafeAreaView style={styles.container}>
<FlatList
data={myData}
renderItem={renderItem}
showsHorizontalScrollIndicator={false}
keyExtractor={(_, index) => index.toString()}
horizontal={true}
onViewableItemsChanged={onViewableItemsChanged}
viewabilityConfig={viewabilityConfig}
/>
</SafeAreaView>
);
The onViewableItemsChanged event callback triggers correctly but after I call setInViewPort so the component updated and it rerendered the below error encounter:
Invariant Violation: Changing onViewableItemsChanged on the fly is not supported
I was looking for the same answer and there is no clear example anywhere. This is how I solved it.
const [inViewPort, setInViewPort] = useState(0)
const viewabilityConfig = useRef({
itemVisiblePercentThreshold: 50,
waitForInteraction: true,
minimumViewTime: 5,
})
const onViewableItemsChanged = React.useRef(({ viewableItems, changed }) => {
if (changed && changed.length > 0) {
setInViewPort(changed[0].index);
}
})
return (
<SafeAreaView style={styles.container}>
<FlatList
data={myData}
renderItem={renderItem}
showsHorizontalScrollIndicator={false}
keyExtractor={(_, index) => index.toString()}
horizontal={true}
onViewableItemsChanged={onViewableItemsChanged.current}
viewabilityConfig={viewabilityConfig.current}
/>
</SafeAreaView>
)
I've got my React-Native app running with Redux and am trying to add nested array items (products) to my store.
How is the Screen suppose to work?
The data from the productScreen is passed on from the previous
screen (selected product)
Loop trough the data and find the nested array and display it in a FlatList
Add/remove selected product to the shopping cart (redux)
Wat works?
The data from the productScreen is passed on from the previous
screen (selected product)
Loop trough the data and find the nested array and display it in a FlatList
What doesn't work is:
Add/remove selected product to the shopping cart (redux)
When I navigate to the screen I get the error this.props.onPress(row) is not a function. this.props.onPress(row)is undefined.
I've tried looking online for solutions and on the official Redux web page, but could not find a way to solve this puzzle. Before I nested the array and displayed the products on separate component that was then loaded onto the page, it did use to work.
Anyone know how to add my nested array to the store?
FlatList
<FlatList
style={styles.listContainer}
data={this.state.filteredProducts}
renderItem={this.renderItem}
keyExtractor={(item, index) => index.toString()}
/>
RenderItem
renderItem = ({item}) => {
let items = [];
if( item.products) {
items = item.products.map(row => {
return (<View key={row.id} style={styles.products}>
<View style={styles.iconContainer}>
<Icon name={row.icon} color="#DD016B" size={25} />
</View>
<View style={styles.text}>
<Text style={styles.name}>
{row.name}
</Text>
<Text style={styles.price}>
€ {row.price}
</Text>
</View>
{console.log('renderItem',this.state.row)}
<View style={styles.buttonContainer} onPress={this.props.addItemToCart} >
<TouchableOpacity onPress={this.props.onPress(row)} >
<Icon style={styles.button} name="ios-add" color="white" size={25} />
</TouchableOpacity>
</View>
<View style={styles.buttonContainer} onPress={this.props.removeItem} >
<TouchableOpacity onPress={() => this.props.onPress(row)} >
<Icon style={styles.button} name="ios-remove" color="white" size={25} />
</TouchableOpacity>
</View>
</View>)
})
}
Adding product to the store
const mapDispatchToProps = (dispatch) =>{
return{
addItemToCart:(product) => dispatch({
type:'ADD_TO_CART', payload: product, qty
}),
removeItem:(product) => dispatch ({
type:'REMOVE_FROM_CART' , payload: product, qty
})
}
}
export default connect(null, mapDispatchToProps) (ProductScreen);
Store.JS
import {createStore} from 'redux';
import cartItems from '../reducers/carItems';
export default store = createStore(cartItems)
cartItems.JS
const cartItems = (state = [], action) => {
switch (action.type)
{
case 'ADD_TO_CART':
// console.log('CarItems.JS', action.payload)
if (state.some(cartItem => cartItem.id === action.payload.id)) {
// increase qty if item already exists in cart
return state.map(cartItem => (
cartItem.id === action.payload.id ? { ...cartItem, qty: cartItem.qty + 1 } : cartItem
));
}
return [...state, { ...action.payload, qty: 1 }]; // else add the new item to cart
case 'REMOVE_FROM_CART':
return state
.map(cartItem => (cartItem.id === action.payload.id ? { ...cartItem, qty: cartItem.qty - 1 } : cartItem))
.filter(cartItem => cartItem.qty > 0);
}
return state
}
export default cartItems
It looks like you are passing the result of a function call into the onPress prop of TouchableOpacity.
You might want to try changing
<TouchableOpacity onPress={this.props.onPress(row)} >
to
<TouchableOpacity onPress={() => this.props.onPress(row)} >
as you have done in the second case.
Hi I'm making an api request, rendering results using FlatList like this:
<TouchableOpacity onPress={this._onPressButton}>
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<TouchableOpacity
activeOpacity={0.8}
onPress=this._onPressButton}>
<ListItem
title= {`${item.companyName}`}
subtitle= {`[ ${item.symbol} ] ${item.change}%`}
/>
</TouchableOpacity>
my goal is to access data on specific rows, let's suppose I created a function that make an alert:
_onPressButton = () => {
alert('What should search for here?')
};
How to access item.companyName ?
You could:
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<TouchableOpacity
activeOpacity={0.8}
onPress={()=>this._onPressButton(item.companyName)}>
<ListItem
title= {item.companyName}
subtitle= {`[ ${item.symbol} ] ${item.change}%`}
/>
with
_onPressButton = (companyName) => {alert(companyName)};
I use a RootForm as the basic template for form page. There is one field associated with location autocomplete, so I wrap the native autocomplete of react-native and use it in that field. However, the autocomplete dropdown list is blocked by other fields in the form which are rendered behind it. I try to search online but no useful materials. Using modal or zIndex is not the solution here. How could I make the dropdown list on the top of other components even if it renders earlier than other components?
The following two snippets are my rootform and autocomplete render functions.
render() {
const { input } = this.state;
const cities = this.state.cities;
return (
<View style={styles.container}>
<Autocomplete
autoCapitalize="none"
autoCorrect={false}
containerStyle={styles.autocompleteContainer}
data={cities}
defaultValue={input}
onChangeText={text => this.setState({ input: text })}
placeholder="Enter Location"
renderItem={({ cityName, cityId }) => (
<TouchableOpacity style={styles.listStyle} onPress={() => this.setState({ input: cityName, cities: [] })}>
<Text style={styles.itemText}>
{cityName}
</Text>
</TouchableOpacity>
)}
/>
</View>
);
}
render() {
const data = this.props.data;
let fields = [];
let onPress = null;
Object.keys(data).forEach((key, index) => {
let options = data[key].options ?
data[key].options : null
if ("type" in data[key]) {
fields.push(
<View style={styles.formField} key={key}>
<Text style={styles.text}>{data[key].label}</Text>
<AutoComplete />
</View>
)
} else {
let custom = [styles.formField];
if (options) {
fields.push(
<View style={custom} key={key}>
<Text style={styles.text}>{data[key].label}</Text>
<TextInput value={data[key].value} style={styles.input}
readOnly
{...options} />
</View>
)
} else {
fields.push(
<View style={custom} key={key}>
<Text style={styles.text}>{data[key].label}</Text>
<TextInput value={data[key].value} style={styles.input}
onChangeText={(text) => this.props.onFieldChange(key, text)}
{...options} />
</View>
);
}
}
})
return (
<KeyboardAwareScrollView style={styles.container}>
{fields}
</KeyboardAwareScrollView>
)
}
You can just change your style.container to have a higher zIndex than whatever is appearing on top of it. However this will have the other items in the form appear behind the area reserved for the dropdown list, and render them unselectable.
If you want items underneath the Autocomplete component's area to still be interactive/selectable, you can use React.useState in order to have a dynamic zIndex property on your component.
const [componentZIndex, setComponentZIndex] = React.useState(1);
You will want your components behind the area reserved for the list to have a zIndex higher than 2 so that they are interactive.
Then you'll want to render your own input component so that you have access to the onFocus property. Luckily, the library you are using allows you to do this:
renderTextInput={() => (
<View style={styles.input}>
<TextInput
onFocus={() => setComponentZIndex(999)}
value={value}
/>
</View>
)}
This will bring the list to the top whenever the user is using the autocomplete component. The last thing to do is to make sure that you push it to the back once the user is no longer using it.
React.useEffect(() => {
Keyboard.addListener('keyboardDidHide', _keyboardDidHide);
return () => {
Keyboard.removeListener('keyboardDidHide', _keyboardDidHide);
};
}, []);
const _keyboardDidHide = () => {
setComponentZIndex(1)
};