I am asking something that is probably trivial but that has been bugging me for a while.
Lets say we have a CHILD component that renders some buttons:
const Picker = ({ data, label, visible, cancelCallback, onPressCallback }) => {
function renderRow (data) {
return data.map((el) => {
return (
<TouchableOpacity
style={listViewItemContainer}
key={el.label}
onPress={}
>
<Text style={listViewItem}> { el.label } </Text>
</TouchableOpacity>
);
});
}
return (
<Modal
visible={visible}
animationType="fade"
onRequestClose={() => {}}
transparent={true}
>
<View style={listViewContainerStyle}>
{ renderRow(data) }
</View>
</Modal>
);
};
Now when I press one of those buttons I want to make a callback to the parent BUT I want to pass some parameters like the label of the element pressed. Something like:
<TouchableOpacity
style={listViewItemContainer}
key={el.label}
onPress={onPressCallback(el.label)} // onPressCallback is a Prop passed to the child
>
<Text style={listViewItem}> { el.label } </Text>
</TouchableOpacity>
And then handle the logic in the parent component.
How can I do this?
Like this.
onPress={() => onPressCallback(el.label)}
Related
So I have a homescreen that renders a modal component. I use some states for modal visibility. However, the problem is that when I navigate from the modal to another screen and then back to my home screen, the modal is still opened and I cannot figure out how to close it. I tried using useEffect but it does not do anything. Any tips?
This is home screen.
The AddButton component is a simple TouchableOpacity that onPress call the toggleModal function
const [isModalVisible, setIsModalVisible] = useState(false);
const toggleModal = () => {
setIsModalVisible(!isModalVisible);
};
useEffect(() => {
setIsModalVisible(false)
}, [navigation])
return (
<AddButton
title="ADD BOOK"
toggleModal={toggleModal}
/>
)
And the Modal Component is this:
const ModalComponent = ({navigation, isModalVisible, toggleModal, title, author, save, onNavigate }) => {
return (
<Modal isVisible={isModalVisible}>
<View style={styles.container}>
<Text>Modal</Text>
<View style={styles.footer}>
<TouchableOpacity onPress={toggleModal}>
<Text>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate("AddBookScreen")}>
<Text>{save}</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
);
};
Modify this code
<TouchableOpacity onPress={() => navigation.navigate("AddBookScreen")}>
<Text>{save}</Text>
</TouchableOpacity>
to
<TouchableOpacity onPress={() => {
navigation.navigate("AddBookScreen")
toggleModal();
}}>
<Text>{save}</Text>
</TouchableOpacity>
extract onPress function and move it up to your page and pass it as onSaveClick callback to the modal component.
// on your page
const onSaveClick = () => {
navigation.navigate("AddBookScreen")
setIsModalVisible(false)
}
then in the modal
<TouchableOpacity onPress={onSaveClick}>
<Text>{save}</Text>
</TouchableOpacity>
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.
This TouchableOpacity component: <TouchableOpacity onPress={props.goToDetails()}> takes props from its parent function, in this code, when calling the function goToDetails my code only works and shows the right results when using parenthesis, while sometimes when I just use the name of the function -in the class-, the code works fine without parenthesis: onPress={this.goToDetails}.
This is the full code,
In the class:
render(){
return (
<View>
<MovieList results ={this.state.searchResults} goToDetails={()=>this.goToDetails} />
</View>
)}
goToDetails=()=>{
this.props.navigation.navigate('Details')
}
Independent function:
const MovieList = props =>{
const renderItem = ({item}) =>(
<TouchableOpacity onPress={props.goToDetails()}>
<Image source={{uri:`http://img.omdbapi.com/?apikey=&`}} style={{height:200, width:200}} />
<Text>Title: {item.Title}</Text>
</TouchableOpacity>)
return (<FlatList style={{flex:1}} renderItem={renderItem} data={props.results} />) }
UPDATE:
The class calling MovieList code, the TouhcableOpacity code
You pass goToDetails callback inconsistently.
When you goToDetails={()=>this.goToDetails} this is a callback that returns a function, so in Movielist when it's attached to a handler as onPress={props.goToDetails()} it needs to be invoked immediately in order to get the returned function in order to again have a signature of onPress={callbackFn} or onPress={e => callbackFn(e)}.
render(){
return (
<View>
<MovieList
results={this.state.searchResults}
goToDetails={this.goToDetails} /> // Pass callback as reference
</View>
)}
goToDetails=()=>{
this.props.navigation.navigate('Details')
}
MovieList
const MovieList = ({ goToDetails }) =>{
const renderItem = ({ item }) =>(
<TouchableOpacity onPress={goToDetails}> // Attach callback to event handler
<Image
source={{ uri:`http://img.omdbapi.com/?apikey=&` }}
style={{ height:200, width:200 }}
/>
<Text>Title: {item.Title}</Text>
</TouchableOpacity>
);
return (
<FlatList
style={{ flex:1 }}
renderItem={renderItem}
data={props.results}
/>
);
}
Calling navigation.navigate('DrawerOpen') from inside a HOC doesn't open the drawer menu
I have written a higher order component which returns a screen with header for drawer navigator.
Header
const Header = (props)=>{
return (
<View style={{flex:1,backgroundColor:"red",justifyContent:"center"}}>
<TouchableWithoutFeedback onPress={() => {
props.navigation.navigate('DrawerOpen');
if (props.navigation.state.index === 0) {
props.navigation.navigate('DrawerOpen')
} else {
props.navigation.navigate('DrawerClose')
}
}}>
<View >
<Text style={{fontSize:20,color:"white"}}>{"Menu"}</Text>
</View>
</TouchableWithoutFeedback>
</View>
);
}
HOC
const createCompWithHeader = (Comp)=>{
return (props)=>{
return (
<View style={{flex:1,marginTop:20}}>
<Header {...props}/>
<View style={{flex:9}}>
<Comp {...props}/>
</View>
</View>
);
}
}
Drawer Navigator
const MyApp = DrawerNavigator({
Home: {
screen: createCompWithHeader(MyHomeScreen),
},
Notifications: {
screen: createCompWithHeader(MyNotificationsScreen),
},
});
Components(Screens)
class MyHomeScreen extends Component {
static navigationOptions = {
drawerLabel: 'Home'
};
render() {
return (
<View>
<Button
onPress={()=>this.props.navigation.navigate('DrawerOpen')}
title={"Open menu"}
/>
<Button
onPress={() => this.props.navigation.navigate('Notifications')}
title="Go to notifications"
/>
</View>
);
}
}
class MyNotificationsScreen extends Component {
static navigationOptions = {
drawerLabel: 'Notifications'
};
render() {
return (
<View>
<Button
onPress={()=>this.props.navigation.navigate('DrawerOpen')}
title={"Open Menu"}
/>
<Button
onPress={() => this.props.navigation.goBack()}
title="Go home"
/></View>
);
}
}
Current Behavior
when I click on the button in header(props.navigation.navigate('DrawerOpen')), the drawer menu doesn't open
When I click on the button inside the component, menu opens
Expected Behavior
On click of the button in the header, menu should open.
How to reproduce
Expo Url : Snack
Environment
| react-navigation |1.5.8
| react-native |0.55.2
After 2.0 release, rather than opening a drawer with navigation.navigate(‘DrawerOpen’), you can now call navigation.openDrawer().
Other methods are closeDrawer() and toggleDrawer().
I've checked your snack expo and the problem lies in this snippet
if (props.navigation.state.index === 0) {
props.navigation.navigate('DrawerOpen')
} else {
props.navigation.navigate('DrawerClose')
}
The navigation does not add an index to the state, therefore it's value remains undefined
So what you are doing is , Opening and Closing the drawer yourself
Therefore remove this snippet to see it work.
onPress={() => props.navigation.navigate('DrawerOpen')}
I am trying to add a function to return button text based on the state inside the renderItem FlatList component.
renderButton() {
return <Text>Button</Text>;
}
<TouchableWithoutFeedback>
<TouchableOpacity>
{this.renderButton()}
</TouchableOpacity>
<TouchableWithoutFeedback>
This code return an error
function this.renderButton is not a function
Update:
<FlatList
data={list}
renderItem={this.renderRow}
/>
renderRow({item}) {
return(
<TouchableWithoutFeedback>
<TouchableOpacity>
{this.renderButton()}
</TouchableOpacity>
<TouchableWithoutFeedback>
);
}
renderButton() {
return <Text>Button</Text>;
}
You need to bind the renderRow function to be able to access this.renderButton in it.
<FlatList
data={list}
renderItem={this.renderRow.bind(this)}
/>
or
<FlatList
data={list}
renderItem={() => this.renderRow()}
/>
or
renderRow = ({item}) => {
return(
<TouchableWithoutFeedback>
<TouchableOpacity>
{this.renderButton()}
</TouchableOpacity>
<TouchableWithoutFeedback>
);
}