Flatlist TouchableHighlight passing value - javascript

i wanna implement a page able to list some categories and once clicked, do some other tasks.
I've tried to implement it like I'm doing here but when I render the page, category is automatic chosen and it is set to last value.
What i wrong?
Here my code
const data = [
{category: 'a'},
{category: 'b'},
{category: 'c'},
];
<FlatList
data={data}
renderItem={({item}) => (
<View style={categoryStyles.itemContainer}>
<TouchableHighlight style={{ }} selectedCategory={item.category}
onPress={this._nextStep(item.category)}>
<View style={{alignItems:'center', justifyContent: 'space-around',}}>
<Icon name={item.icon} size={40}/>
<Text style={categoryStyles.item}>{item.description}</Text>
</View>
</TouchableHighlight>
</View>
)}
keyExtractor={item => item.id}
numColumns={numColumns} />
_nextStep = (selectedCategory) => {
if (this.state.index !== this.props.children.length - 1) {
this.setState(prevState => ({
index: prevState.index + 1,
}));
this.setState(() => ({
selectedCategory: selectedCategory,
}));
}
};

You just need to change this
onPress={this._nextStep(item.category)}
To
onPress={()=> this._nextStep(item.category)}

Related

How do I display items in a nested array in react native?

I am working on a project in react native and how the program should work is that the user will start at RestaurantScreen.js and then once they pick a restaurant they will move to the next screen, MenuScreen.js. I want each restaurant to display the specific meal inside the nested array productData array in data.js. Right now the RestaurantScreen.js displays all the restaurants from the array restaurantData inside data.js but once you click on a restaurant it displays all the meals from each restaurant, but I just want the one meal, price, and image. Let me know if I need to provide move info.
data.js
export const restaurantData = [
{restaurantName:"Milan Mondayz",
businessAddress:"The Steak House of Hammond",
images:require('../images/milanpic.jpg'),
productData:[{
meal:"BBQ Chicken Plate with Sides",
foodImages:require('../images/Food1.jpg'),
price:12.00,
checked:false,id:"0"}],
id:"0"},
{restaurantName:"Nick's Cajun Flavors",
businessAddress:"123 Hammond Road",
images:require('../images/cajun.jpeg'),
productData:[{
meal:"Crawfish Etouffee",
price:13.99,
foodImages:require('../images/crawfishEto.jpeg'),
checked:false}],
id:1},
];
RestaurantScreen.js
export default function RestaurantScreen({ navigation }) {
const [indexCheck, setIndexCheck] = useState("0")
const { navigate } = useNavigation();
return (
<View style={styles.container}>
<View style={styles.cardView}>
{/*<Button
title="Go to Menu"
onPress ={()=>{navigation.navigate("Menu",{restaurantData})}}
/>*/}
<View style ={styles.headerTextView}>
<Text style ={styles.headerText}>Where Do You Want To Eat?</Text>
</View>
<View>
<FlatList
style={{marginTop:10, marginBottom:10}}
data={restaurantData}
vertical ={true}
keyExtractor={(restaurantData => restaurantData.id)}
extraData={indexCheck}
renderItem={({ item, index }) => (
<RestaurantCard
screenWidth={SCREEN_WIDTH*.94}
images={item.images}
restaurantName={item.restaurantName}
businessAddress={item.businessAddress}
//productData={item.productData}
OnPressRestaurantCard ={()=>{navigation.navigate("Menu",{index});
}}
/>
)}
showsVerticalScrollIndicator={false}
/>
</View>
</View>
</View>
)
}
MenuScreen.js
export default class MenuScreen extends Component {
render() {
const index = this.props.route.params.index
//const {meal,price,foodImages} = restaurantData[index]
return (
<View style={styles.container}>
<View style={styles.cardView}>
<View style ={styles.headerTextView}>
<Text style ={styles.headerText}>What Do You Want To Eat From?</Text>
</View>
<TouchableOpacity onPress={() => {this.props.navigation.navigate('Cart')}}>
<View style ={styles.cartContainer}>
<View style ={styles.cartCounterContainer}>
<Text style ={styles.cartText}>Cart</Text>
<View style ={styles.cartCounter}>
<Text style ={styles.cartNum}>0</Text>
</View>
</View>
</View>
</TouchableOpacity>
<View>
<View style ={{flex:1}}>
<View style ={styles.menuCard}>
<FlatList
style={{marginTop:10, marginBottom:10}}
data = {restaurantData}
keyExtractor= {item =>item.id}
renderItem = {({item,index})=>(
<MenuCard
screenWidth={SCREEN_WIDTH*.9}
images={item.foodImages}
meal ={item.meal}
price ={item.price}
onPressMenuCard={()=>{this.props.navigation.navigate("Payment")}}
/>
)}
/>
</View>
</View>
</View>
</View>
</View>
)
}
}
I can do it with SectionList and this is my example: https://snack.expo.dev/#pqv2210/exsectionlist
Just change name of field in your restaurantData: productData to data
export const restaurantData = [
{
restaurantName: 'Milan Mondayz',
businessAddress: 'The Steak House of Hammond',
images: require('../images/milanpic.jpg'),
data: [
{
meal: 'BBQ Chicken Plate with Sides',
foodImages: require('../images/Food1.jpg'),
price: 12.0,
checked: false,
id: '0',
},
],
id: '0',
},
{
restaurantName: "Nick's Cajun Flavors",
businessAddress: '123 Hammond Road',
images: require('../images/cajun.jpeg'),
data: [
{
meal: 'Crawfish Etouffee',
price: 13.99,
foodImages: require('../images/crawfishEto.jpeg'),
checked: false,
},
],
id: 1,
},
];
Replace FlatList to SectionList and modify RestaurantCard is item of list in renderItem.
const renderRestaurentInfo = ({ section }) => (
// render restaurantName, images and businessAddress
)
const renderFoodItem = ({ item }) => (
// render meal, foodImages, price
)
<SectionList
sections={restaurantData}
renderSectionHeader={renderRestaurentInfo}
keyExtractor={(_, index) => index + ''}
renderItem={renderFoodItem}
/>

How to update Flatlist Choice

Absolute react-native noob here. I am struggling with updating the 'selected item'. I'm using this as a piece of dummy data:
this.state = {
branch: '',
completedBy: '',
reportedTo: '',
branchData: {
text: 'Branch',
value: '',
options: [
{code: '0001', name: 'TEST 1', key: 1},
{code: '0002', name: 'TEST 2', key: 2},
{code: '0003', name: 'TEST 3', key: 3},
]
}
};
I then made a separate file for my dropdown component, it looks like this:
super(props);
this.state = {
modalVisible: false
};
}
render() {
return (
<>
<TouchableWithoutFeedback style={styles.refreshBtn} onPress={() => this.setState({ modalVisible: true })} >
<View style={styles.container} >
{
this.props.data.value ?
<Text style={styles.selectedText} >{this.props.data.value}</Text>
:
<Text style={styles.placeholderText} >{this.props.data.text}</Text>
}
<MaterialCommunityIcons name={'chevron-down'} size={30} color={Colors.grey} />
</View>
</TouchableWithoutFeedback>
<Modal
animationType="slide"
visible={this.state.modalVisible}
onRequestClose={() => {
this.setState({ modalVisible: false })
}}
>
<TouchableOpacity onPress={() => this.setState({ modalVisible: false })} style={{ flexDirection: "row", justifyContent: "flex-end", margin: 10, paddingLeft: 50}}>
<Ionicons name="md-close" size={30} />
</TouchableOpacity>
<FlatList
data={this.props.data.options}
keyExtractor={(item) => item.key.toString()}
renderItem={({ item }) => (
<TouchableOpacity style={styles.itemContainer} onPress={() => console.log('tapped'} >
<Text style={styles.itemText}>{item.code + ' ' + item.name}</Text>
</TouchableOpacity>
)}
/>
</Modal>
</>
);
}
}
And then back to my initial file, I am simply calling the component like this:
<DropDownMenu data={this.state.branchData}/>
How do I update the value in the branch data object in order to display the selected branch on the dropdown in order to indicate to the user that their choice has been selected instead of displaying the placeholder text which displays as long as value is = to an empty string.
You can pass down a state updating function as a prop to your DropDownMenu component, add this function to the same file where state has been initialized
function updateBranch(dataFromDropDownComponent) {
// modify branch data as required
// this.setState({...this.state, branchData: ... })
}
and then in JSX, pass it as a prop:
<DropDownMenu data={this.state.branchData} updateBranch={updateBranch}/>
Now in your DropDownMenu component, you can access and call the updateBranch function via this.props.updateBranch to update the state whenever required.

React native single selectable components

I am trying to achieve a simple single selectable item, as shown in the image below.
Right now, I have created an array of my data items and using .map to render the components because there are only 3-4 items max, now I want to select only a single item and change the color on the basis, and if I select any other item, it should unselect all the other items but not the current single selected item/component. I tried to do this but I am able to select all of them, obviously. Below is the code:
const items = [
{
id: 1,
iconName: 'male',
title: 'Male',
name: 'male',
},
{
id: 2,
iconName: 'female',
title: 'Female',
name: 'female',
},
{
id: 3,
iconName: 'transgender',
title: 'Others',
name: 'others',
},
];
const Component = ({dispatch, iconName, title, name}) => {
const [isSelected, setIsSelected] = useState(false);
return (
<TouchableOpacity
activeOpacity={0.6}
style={
isSelected
? [styles.selectable, {backgroundColor: 'green'}]
: [styles.selectable, {backgroundColor: COLORS.PINK}]
}
onPress={() => {
setIsSelected(!isSelected);
}}>
<View style={styles.row}>
<Ionicon name={iconName} size={36} color="#fff" />
<Text>{title}</Text>
</View>
</TouchableOpacity>
);
};
const Gender = () => {
return (
<View>
<View>
<Text>Your Gender</Text>
<View>
{items.map(item => (
<Component
key={item.id}
title={item.title}
iconName={item.iconName}
/>
))}
</View>
</View>
</View>
);
};
All though I could solve this by using separate states for each button, so whenever one is selected/pressed, the other states should become false. But then I would have to render individual component without using the .map method which I find inefficient. Can someone provide any solution based on my current approach to this problem?
Thank you!
Consider moving isSelected to the parent component, and instead of storing a booolean, store the selected item id. Pass the itemId, selectedId, setSelectedId (as a callback) to the child components and change the style check to:
style={
itemId === selectedId
? [styles.selectable, {backgroundColor: 'green'}]
: [styles.selectable, {backgroundColor: COLORS.PINK}]
}
onPress={() => {
setSelectedId(itemId);
}}>
Now you can get rid of keeping track whether the item is selected in the component, and only worry about it in the context of the parent (as it should be).
const Gender = () => {
const [selectedId, setSelectedId] = useState(false);
return (
<View>
<View>
<Text>Your Gender</Text>
<View>
{items.map(item => (
<Component
key={item.id}
itemId={item.id}
selectedId={selectedId}
setSelectedId={setSelectedId}
title={item.title}
iconName={item.iconName}
/>
))}
</View>
</View>
</View>
);
};

React-native adding components to array and accessing them

I'm trying to make some sort of quiz, and I want to have all the boxes in a FlatList. I want all of them to be hidden, except for the first one, and that when you answer it the next question appears.
Here is my code:
const TYPE = [{id:"1",title:"first question",options:["option 1","option 2"],correct:1},{id:"2",title:"secondquestion",options:["option 1","option 2"],correct:0}];
const answer=a=>Alert.alert(a == 0 ? 'wrong' : 'correct');
const Item = ({info}) => (
<View style={styles.item}>
<Text style={styles.title}>
{info.title}
</Text>
<TouchableOpacity style={styles.button} onPress={() => info.correct == 0 ? answer(1) : answer(0)}>
<Text>
{info.options[0]}
</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={() => info.correct == 1 ? answer(1) : answer(0)}>
<Text>
{info.options[1]}
</Text>
</TouchableOpacity>
</View>
);
function HomeScreen({ navigation }) {
return (
<View style={styles.homescreen}>
<Text style={styles.homeTitle}>
Welkom!
</Text>
<Text style={styles.homeIntro}>
Play the test, yes?
</Text>
<TouchableOpacity style={styles.homeButton} onPress={() => navigate(navigation, "Type")}>
<Text style={styles.homeButtonText}>
Start the Test!
</Text>
</TouchableOpacity>
</View>
)
}
function type() {
const renderItem = ({ item }) => <Item info={item} />;
return (
<View style={styles.container}>
<FlatList
data={TYPE}
renderItem={renderItem}
keyExtractor={item => item.id}
style={styles.list}
/>
<StatusBar style="auto" />
</View>
);
}
export default function App() {
console.log("Starting...");
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Type" component={type} />
</Stack.Navigator>
</NavigationContainer>
)
}
My approach to this would be to add all s into an array, so that I can simply do this: itemArray[i].style.display='None' or something like that.
Try below code that could help to achieve what you want:
import React from 'react';
import {
Alert,
StatusBar,
Text,
TouchableOpacity,
View,
} from 'react-native';
const TYPE = [
{
id: '1',
title: 'first question',
options: ['option 1', 'option 2'],
correct: 1,
},
{
id: '2',
title: 'secondquestion',
options: ['option 1', 'option 2'],
correct: 0,
},
];
const Item = ({info, onPressOption}) => (
<View style={styles.item}>
<Text style={styles.title}>{info.title}</Text>
<TouchableOpacity style={styles.button} onPress={() => onPressOption(0)}>
<Text>{info.options[0]}</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={() => onPressOption(1)}>
<Text>{info.options[1]}</Text>
</TouchableOpacity>
</View>
);
function HomeScreen({navigation}) {
return (
<View style={styles.homescreen}>
<Text style={styles.homeTitle}>Welkom!</Text>
<Text style={styles.homeIntro}>Play the test, yes?</Text>
<TouchableOpacity
style={styles.homeButton}
onPress={() => navigate(navigation, 'Type')}>
<Text style={styles.homeButtonText}>Start the Test!</Text>
</TouchableOpacity>
</View>
);
}
function QuestionScreen({navigation}) {
const [activeQuestionIndex, setActiveQuestionIndex] = React.useState(0);
const showAlert = (isCorrect, onPress) => {
Alert.alert(isCorrect ? 'correct' : 'wrong', null, [
{
onPress,
},
]);
};
const onPressOption = (optionIndex) => {
const isCorrectOption = TYPE[activeQuestionIndex].correct === optionIndex;
showAlert(isCorrectOption, () => {
isCorrectOption && setActiveQuestionIndex(activeQuestionIndex + 1);
});
};
return (
<View style={styles.container}>
<StatusBar style="auto" />
<Item info={TYPE[activeQuestionIndex]} onPressOption={onPressOption} />
</View>
);
}

React Native, error looping through an array (Failed child context type:)

I have the below code to loop through an array.
export default function App() {
const [x, setX] = useState([
{name:'a'},{name:'b'}
]);
return (
<View >
<FlatList
data={x}
renderItem={(item) => {
return <Text>{item.name}</Text>;
}}
/>
</View>
);
The above code gives below error
Warning: Failed child context type: Invalid child context `virtualizedCell.cellKey` of type `number` supplied to `CellRenderer`, expected `string`.
When I change
<FlatList
data={x}
renderItem={(item) => {
return <Text>{item.name}</Text>;
}}
/>
To
<FlatList
data={x}
renderItem={({item}) => {
return <Text>{item.name}</Text>;
}}
/>
The code is correct now and it works, see I changed (item) to ({item}) added curly braces .
Why is so ?
As you can see link document https://reactnative.dev/docs/flatlist.html
renderItem
renderItem({ item, index, separators });
item: (Object): The item from data being rendered.
index (number): The index corresponding to this item in the data array.
separators (Object)
highlight (Function)
unhighlight (Function)
updateProps (Function)
select (enum('leading', 'trailing'))
newProps (Object)
Example usage:
<FlatList
ItemSeparatorComponent={
Platform.OS !== 'android' &&
(({ highlighted }) => (
<View
style={[
style.separator,
highlighted && { marginLeft: 0 }
]}
/>
))
}
data={[{ title: 'Title Text', key: 'item1' }]}
renderItem={({ item, index, separators }) => (
<TouchableHighlight
key={item.key}
onPress={() => this._onPress(item)}
onShowUnderlay={separators.highlight}
onHideUnderlay={separators.unhighlight}>
<View style={{ backgroundColor: 'white' }}>
<Text>{item.title}</Text>
</View>
</TouchableHighlight>
)}
/>
you should use the key prop flour. try again with the code below
<FlatList
data={x}
renderItem={({ item, index }) => (
<Text key={index}>{item.name}</Text>
)}
keyExtractor={(item, index) => index.toString()}
/>
Because the FlatList returns item object in which their is your items or array to be render!
its like
{
items: {
{name:'a'},
{name:'b'}
}
}
so we have to go to item first by destructuring by {item} and then access the inner objects.
Hope it will make understanding !

Categories

Resources