How to implement onPress in menu.item? native-base#3.2.1-rc.1 - react-native

For some reason there's no nativeBase api or documentation on this. I can not get a menu.item to respond to press/click no matter what I try.
Attempts
putting Text/Button elements from react-native into the menu. item
putting the menu in multiple different screens
creating a separate function instead of just arrow function
import React from "react"
import {
Menu,
HamburgerIcon,
Box,
Center,
NativeBaseProvider,
usePropsResolution,
Text,
Pressable
} from "native-base"
import {Alert, } from "react-native";
import { logout } from "../_redux/_actions/authentication.actions";
export const NavMenu = (props) => {
const menuItems = ['Profile','Sign Out'];
return (
<Box h="80%" w="95%" alignItems="flex-start">
<Menu w="150" top="-85" h="100%"
trigger={(triggerProps) => {
return (
<Pressable accessibilityLabel="More options menu" {...triggerProps}>
<HamburgerIcon color="black" />
</Pressable>
)
}}
>
**<Menu.Item onPress={()=>alert("Alert Title")}>**
Logout
</Menu.Item>
</Menu>
</Box>
)
}
export default () => {
return (
<NativeBaseProvider>
<Center flex={1} px="1">
<NavMenu />
</Center>
</NativeBaseProvider>
)
}

I found workaround around this problem. Would be interested in better solution, but this should work (it is also not very clean solution):
<Menu.Item onPress={()=>alert("Alert Title")}>
<Pressable onPress={()=>alert("Alert Title")}><Text>Logout</Text></Pressable>
</Menu.Item>
Basically what I am doing here is putting onPress to the Menu.Item and then same onPress to the child. You can use this approach for more complicated situations like adding button to the menu like this:
<Menu.Group title="Účet">
<Menu.Item onPress={() => console.log('log')}>
<Button colorScheme="red" onPress={() => console.log('log')} leftIcon={<Icon size="s" as={<MaterialIcons name='logout' />} />}>
Logout
</Button>
</Menu.Item>
</Menu.Group>

Related

How to pass a function to a react native custom component but not run until onPress

I am new to RN. WRiting my first app. I read the docs on passing functions but am unclear on how to solve my issue. I have built myself a custom button component.
import React from 'react'
import { View, TouchableOpacity, Text } from 'react-native'
import { Theme } from '../Styles/Theme';
import { AntDesign } from '#expo/vector-icons'
export const CButton = ({text, icon = null, iconSide = null, onPress}) => {
return (
<TouchableOpacity onPress={onPress} >
<View style={Theme.primaryButton}>
{iconSide == "left" && icon &&
<AntDesign style={Theme.primaryButtonIcon} name={icon} size={24} color="white" />
}
<Text style={Theme.primaryButtonText}>{text}</Text>
{iconSide == "right" && icon &&
<AntDesign style={Theme.primaryButtonIcon} name={icon} size={24} color="white" />
}
</View>
</TouchableOpacity>
)
}
I think this is pretty basic stuff.
I am using the button as a login button in this case:
<CButton
text="Login"
icon="right"
iconSide="right"
onPress={login(email, password)}
/>
I am passing login(email, password) to the onPress prop and then using it in my custom component like:
<TouchableOpacity onPress={() => onPress} >
The issue is that as the way I am doing this is calling the function on load (I know thats a web term). Its not waiting until I press the button.
How do I make sure the onPress only happens when the button is pressed?
TIA
In your way, you are directly calling the login function when component is rendering.
You just need to modify your use of component like this
<CButton
text="Login"
icon="right"
iconSide="right"
onPress={()=> login(email, password)}
/>

One form, but different state

I'm moving now from other technologies to React Native and I have a problem. I have one presentational component which is <TaskInput />.
const TaskInput = (props: ITaskInputProps) => {
return (
<View style={styles.container} >
<Text style={styles.title}>{props.title}</Text>
<TextInput
style={styles.input}
multiline
scrollEnabled={false}
/>
</View>
)
}
ParentComponent over TaskInput
import React from 'react';
import { View } from 'react-native';
import styles from './styles';
import TaskInputContainer from '../task-input';
interface ITaskConfigurationProps {
title: string,
isInputForm?: boolean,
isRequired?: boolean,
}
const TaskConfiguration = (props: ITaskConfigurationProps) => {
return (
<View style={(props.isRequired) ? [styles.container, {backgroundColor: '#f25e5e'}] : styles.container}>
{ props.isInputForm && <TaskInputContainer title={props.title} /> }
</View>
);
}
export default TaskConfiguration;
const TaskScreen = (props: ITaskScreenProps) => {
return (
<View style={styles.container}>
<SectionTitle title={'Task Settings'} />
<ScrollView contentContainerStyle={styles.configurations}>
<TaskConfiguration title={"What you need to do?"} isInputForm={true} isRequired={true} />
<TaskConfiguration title={"Description"} isInputForm={true} />
<TaskConfiguration title={"Deadline"} />
<TaskConfiguration title={"Priority"} />
</ScrollView>
<Button isDone={true} navigation={props.navigation} />
</View>
)
}
TaskInput component takes one prop which is title and it will be in two places on my screen. One component will be called "Enter main task", another one is "Description". But this component will accept different states like currentMainTextInput and currentDescriptionTextInput. This is my idea of re-usable component TextInput, but I can't do what I want because if I set type in one input - other input will re-render with first input (both of them are one presentational component).
I want to use this dumb component in any place of my app. I don't want to create a new identical component and duplicate code, How can I do that? (P.S. I was thinking about "redux or class/hooks", but what should I use...)

React Native: Sidebar is shown but unable to interact with it

I am using React Native Sidebar
This is the sidebar:
<Sidebar
ref={(ref) => this._drawer = ref}
leftSidebar={ this.renderLeftSidebar() }
leftSidebarWidth = {200}
>
</Sidebar>
This is how I'm rendering the left sidebar:
renderLeftSidebar = () =>{
return (
<View style = {{ position:'absolute', backgroundColor:'#24292e4f', height:Dimensions.get('window').height}}>
<DrawerContent/>
</View>
)
}
And this is the content for that left sidebar:
export default DrawerContent = () => {
return (
<View style={styles.animatedBox}>
<Image
source={require('../assets/images/header.png')}
style={{height:200, alignSelf:'center'}}
/>
<View style = {styles.drawerContentView}>
<Icon
name='setting'
type='antdesign'
color='#4abce3'
size ={22}
iconStyle = {styles.drawerItemIconStyle}
onPress={() => console.log('hello settings')}
/>
</View>
The sidebar opens just fine and renders correctly, but when I try and press anything on the sidebar the press goes through the sidebar and interacts with elements rendered beneath it. Should I be using zIndex in my styles or is my approach completely wrong?
If you are using React-native-vector-icons, the ICON itself has no button properties.
You can use Icon.Button
import Icon from 'react-native-vector-icons/AntDesign';
...
<Icon.Button
name='setting'
color='#4abce3'
size ={22}
iconStyle = {styles.drawerItemIconStyle}
onPress={() => console.log('hello settings')}
>
This is Setting
</Icon.Button>
OR You can use TouchableOpacity
import {
TouchableOpacity
} from 'react-native'
import Icon from 'react-native-vector-icons/AntDesign';
...
<TouchableOpacity onPress={() => console.log('hello settings')}>
<Icon
name='setting'
color='#4abce3'
size ={22}
iconStyle = {styles.drawerItemIconStyle}
/>
</TouchableOpacity>

React Native - trigger scrolling of FlatList outside the FlatList

I have a vertical FlatList component and two buttons as TouchableOpacity, how do I perform scrolling of the FlatList with the buttons,
i.e. 'scrolling the FlatList towards bottom` and 'scroll the FlatList towards top'?
Minimal Example:
<View>
<FlatList/>
<TouchableOpacity>
<Text>Scroll towards Top</>Text
</TouchableOpacity>
<TouchableOpacity>
<Text>Scroll towards Bottom</>Text
</TouchableOpacity>
</View>
This is not difficult to accomplish, The <Flatlist/> component already have methods to do that.
scrollToEnd(): Scrolls to the end of the content.
scrollToIndex(): Scrolls to the item at the specified index such 0 which is the top.
I have created a simple demo for you: https://snack.expo.io/#abranhe/flatlist-scroll
I have created a custom <Button/> and <Card/> components. I am creating an array with some random data with this format
const data = [
{ message: 'Random Message' }, { message: 'Random Message' }
]
I am adding a reference to the <Flatlist/> by adding
ref={ref => (this.flatlist = ref)}
Then I call the methods and that's it.
<Button title="▼" onPress={() => this.flatlist.scrollToEnd()} />
The whole source code:
import React from 'react';
import { Text, View, FlatList, StyleSheet } from 'react-native';
import { random } from 'merry-christmas';
import Card from './components/Card';
import Button from './components/Button';
const data = [...Array(10)].map(i => ({ message: random() }));
export default () => (
<View style={styles.container}>
<FlatList
ref={ref => (this.flatlist = ref)}
data={data}
renderItem={({ item }) => <Card gretting={item.message} />}
/>
<View style={styles.bottomContainer}>
<Button
title="▲"
onPress={() => this.flatlist.scrollToIndex({ index: 0 })}
/>
<Button title="▼" onPress={() => this.flatlist.scrollToEnd()} />
</View>
</View>
);
You can use a scrollView component

How to programmatically select text in a TextInput component

Is there a way to programmatically highlight/select text that is inside a TextInput component?
You can use selectTextOnFocus to achieve this. This will ensure that all text inside the TextInput is highlighted when the field is tapped into.
Actually you can, by accessing textInput's method by refs.
<TextInput ref={input => this.myInput = input} selectTextOnFocus style={{height: 100, width: 100}} defaultValue='Hey there' />
and where you want to select all text programmatically you can
this.myInput.focus()
works on iOS, not sure about android.
Reference : http://facebook.github.io/react-native/releases/0.45/docs/textinput.html#selectionstate
I don't know if there's a better way, but I found a workaround. The text has to be focused first. Here's an example
import React { Component } from 'react';
import { Button, TextInput, findNodeHandle } from 'react-native';
import TextInputState from 'react-native/lib/TextInputState';
class MyComponent extends Component {
render() {
return (
<View style={{ flex: 1, }}>
<Button
title="select text"
onPress={() => {
TextInputState.focusTextInput(findNodeHandle(this.inputRef))
}}
</
<TextInput
selectTextOnFocus
ref={ref => this.inputRef = ref}
/>
</View>
);
}
}
I'm here to share my findings. In a List, you might encounter that selectTextOnFocus is broken. In this case you can use this method selection. From React-Native I found this:
In my case I had trouble with the selectTextOnFocus prop in a list. So I had to add a debounce function to work with selection prop.
const [shouldSelect, setShouldSelect] = useState(undefined);
const onFocus = () =>{
setShouldSelect({start:0, end:String(text).length});
}
const focus = useCallback(_.debounce(onFocus,500),[shouldSelect]);
<TextInput
selection={shouldSelect}
onBlur={()=>setShouldSelect(undefined)}
onFocus={()=>focus()}// this is important
selectTextOnFocus
ref={r=>onRef(r)}
keyboardType={'number-pad'}
autoCorrect={false}
blurOnSubmit={false}
returnKeyType={'done'}
underlineColorIos={'transparent'}
underlineColorAndroid={'white'}
allowFontScaling={false}
value={String(text)}
/>
this.inputRef.focus() sets focus to the TextInput component, and then the flag you set in the attributes selectTextOnFocus does the rest.
Note: For those who wants to use selectTextOnFocus short answer. Actually, it works fine in IOS, but doesn't work in Android.
Thanks to Arnav Yagnik; Following is a similar approach in a functional component:
const inputRef = React.useRef(null);
React.useEffect(() => {
if (inputRef.current) {
console.log('focusing !');
inputRef.current.focus();
}
}, []);
return <TextInput
multiline
label="Amount"
selectTextOnFocus
placeholder="Write Count"
value={stockCount.toString()}
/>