React Native form with Formik not firing handleSubmit - javascript

I am building a form in a React Native app using Formik.
The form doesn't fire the handleSubmit when I click on the button:
<ButtonLoading
loading={isLoading || isSubmitting}
label="Salvar"
style={styles.button}
onPress={handleSubmit}
/>
Here is my full code for this form:
import React, { Component, Fragment } from 'react';
import { View, ScrollView } from 'react-native';
import { withFormik } from 'formik';
class Form extends Component {
state = {
isCepChecked: false,
isLoading: false,
isNewAddress: true,
};
onChangeCep = () => {
// Not related to the problem
};
render() {
const { isCepChecked, isLoading } = this.state,
{
values,
errors,
touched,
setFieldValue,
setFieldTouched,
handleSubmit,
isSubmitting,
} = this.props;
return (
<View style={styles.container}>
<ScrollView style={styles.formContainer}>
{!isCepChecked ? (
<Fragment>
<View style={styles.lineContent}>
<InputComponent
label="Digite o CEP"
name="nrCepPre"
value={values.nrCepPre}
error={errors.nrCepPre}
touched={touched.nrCepPre}
onTouch={setFieldTouched}
onChange={setFieldValue}
keyboardType="phone-pad"
mask={'[00000]-[000]'}
/>
</View>
<View style={styles.lineContent}>
<ButtonLoading
isLoading={isLoading || isSubmitting}
label="Avançar"
style={styles.button}
onPress={() => this.onChangeCep()}
/>
</View>
</Fragment>
) : (
<Fragment>
<View style={styles.lineContent}>
<InputComponent
label="CEP"
value={values.nrCep}
mask={'[00000]-[000]'}
editable={false}
/>
</View>
<View style={styles.lineContent}>
<InputComponent
label="Identificação"
name="dsEndereco"
value={values.dsEndereco}
error={errors.dsEndereco}
touched={touched.dsEndereco}
onTouch={setFieldTouched}
onChange={setFieldValue}
/>
</View>
<View style={styles.lineContent}>
<ButtonLoading
loading={isLoading || isSubmitting}
label="Salvar"
style={styles.button}
onPress={handleSubmit}
/>
</View>
</Fragment>
)}
</ScrollView>
</View>
);
}
}
export default withFormik({
mapPropsToValues: (props) => ({
nrCepPre: '',
dsEndereco: '',
nrCep: '',
}),
validationSchema: enderecoSchema,
handleSubmit(values, customObject, bag) {
console.warn('handle');
},
})(Form);

Why not include your handleSubmit() func in your Form class instead by defining it as _hanlderSubmit = (e) = {...} so that there isn't a need for binding it. Then just call it as this._handleSubmit.
You can find more on arrow notation here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Related

const [item1, item2] inside class component (react-native)?

I've been working on a React-Native project.
For export default function App() INSERT 1 to 3 (on code) works.
For export default class App extends Component none of the INSERT's works.
I have to combine them since the modal gives the user the ability to insert text inside the modal and then process the data to console.log and from there use the data.
export default class App extends Component {
{/* INSERT 1 before render also gives error */}
render () {
{/* INSERT 1 */}
const [list, setList] = useState();
const HandleAddList = () => {
console.log(list);
{/* INSERT 1 END */}
return (
<View>
<Modal
animationType = {"slide"}
transparent={false}
visible={this.state.isVisible}>
<View style={styles.ModalContext}>
<View style={styles.ModalNavigation}>
<Text style={[styles.closeText, styles.navText]}
onPress={() => {
this.displayModal(!this.state.isVisible);
}
}> Cancel </Text>
<Text style = {[styles.navHeader, styles.navText] }>
New</Text>
<Text style={[styles.doneText, styles.navText]}
onPress={() => {
this.displayModal(!this.state.isVisible);
{/* INSERT 2 */}
HandleAddList();
{/* INSERT 2 */}
}
}> Done </Text>
</View>
<TextInput
style={styles.inputText}
placeholder='Enter Something...'
{/* INSERT 3 */}
value = {list}
onChangeText={text => setList(text)}
{/* INSERT 3 */}
autoFocus
/>
</View>
</Modal>
{/* Rest of the code */}
</View>
{/* const stylesheets etc. */}
React-native's documentation told me that I can't use const inside a class component. (https://reactjs.org/warnings/invalid-hook-call-warning.html).
INSERT-comments were only for the purpose of the question and testing was done without it...
All the needed modules was imported from 'react-native'
Any solutions? Would be grateful if someone can help...
You can't use Hooks on Class Components, it's only a Functional Components' feature. Instead of that you could use this,I'm not pretty sure about some things but you can fix the errors:
import styles from './styles.css'
export default function App() {
const [list, setList] = useState();
const [isVisible, setIsVisible] = useState(true);
const HandleAddList = () => {
console.log(list);
}
return (
<View>
<Modal
animationType={"slide"}
transparent={false}
visible={isVisible}>
<View style={styles.ModalContext}>
<View style={styles.ModalNavigation}>
<Text style={[styles.closeText, styles.navText]}
onPress={() => {
setIsVisible(!isVisible);
}
}> Cancel </Text>
<Text style={[styles.navHeader, styles.navText]}>
New</Text>
<Text style={[styles.doneText, styles.navText]}
onPress={() => {
setIsVisible(!isVisible);
HandleAddList();
}
}> Done </Text>
</View>
<TextInput
style={styles.inputText}
placeholder='Enter Something...'
value={list}
onChangeText={text => setList(text)}
autoFocus
/>
</View>
</Modal>
</View>
)
}
I'm not used to Class Components, but I think this can guide you:
export default class App extends Component {
constructor() {
super()
this.state = {
isVisible: true,
list: ""
}
}
HandleAddList () {
console.log(this.state.list);
}
render () {
return (
<View>
<Modal
animationType={"slide"}
transparent={false}
visible={this.state.isVisible}>
<View style={styles.ModalContext}>
<View style={styles.ModalNavigation}>
<Text style={[styles.closeText, styles.navText]}
onPress={() => {
this.setState({...this.state, isVisible: !this.state.isVisible});
}
}> Cancel </Text>
<Text style={[styles.navHeader, styles.navText]}>
New</Text>
<Text style={[styles.doneText, styles.navText]}
onPress={() => {
this.setState({...this.state, isVisible: !this.state.isVisible});
this.HandleAddList();
}
}> Done </Text>
</View>
<TextInput
style={styles.inputText}
placeholder='Enter Something...'
value={this.state.list}
onChangeText={text => this.setState({ ...this.state, list: text})}
autoFocus
/>
</View>
</Modal>
</View>
)
}
}
It's so important you read the documentation (https://es.reactjs.org/docs/state-and-lifecycle.html) by yourself, there's a pair of things here you could fix reading it. It's a pleasure to help anyway, hope this works for you.

Props through React Navigation Drawer

I`m developing an APP for a championship and I have a HomeScreen where the Manager should LOGIN so he/she can update the results.
My problems is: I have a Drawer Navigator and a static password.
How can I get the prop isAdmin to the other screens??
Situation Example:
Screen named 'Points' has a Text Input which enabled status will depend on a function that evaluates if isAdmin= true.
HomeScreen:
export default function Login(){
const [senha, setSenha] = useState('');
var isAdmin = false;
function passCheck(pass){
if(pass == 'Adminlaje'){
isAdmin=true;
alert('Signed In !')
}
else
alert('Wrong password !');
}
return(
<SafeAreaView>
<TextInput
value = {senha}
onChangeText = { (senha) => setSenha(senha) }
/>
<TouchableOpacity onPress = {() => passCheck(senha)}>
<Text>Entrar</Text>
</TouchableOpacity>
</SafeAreaView>
);
}
My Drawer:
const Screens = ({navigation}) =>{
return(
<Stack.Navigator>
<Stack.Screen name = 'HomeScreen' component ={Login}
options={{
headerLeft: () =>(
<TouchableOpacity style = {styles.button} onPress = {()=> navigation.toggleDrawer()}>
<Entypo name="menu" size={35} color="black" />
</TouchableOpacity>
)
}}>
</Stack.Screen>
<Stack.Screen name = 'Points' component ={Points}
options={{
headerLeft: () => (
<TouchableOpacity style = {styles.button} onPress = {()=> navigation.toggleDrawer()}>
<Entypo name="menu" size={35} color="black" />
</TouchableOpacity>
),
}}
>
</Stack.Screen>
</Stack.Navigator>
);
};
const DrawerContent = (props) => {
return(
<DrawerContentScrollView {...props}>
<SafeAreaView>
<DrawerItem
label='HomeScreen'
onPress = {() => props.navigation.navigate('Login')}
/>
<DrawerItem
label='Points'
onPress = {() => props.navigation.navigate('Points')}
/>
</SafeAreaView>
</DrawerContentScrollView>
)
}
export default () => {
return(
<Drawer.Navigator
initialRouteName = 'Login'
drawerContent={props => <DrawerContent {...props}/>}
>
<Drawer.Screen name = 'Screens' component ={Screens}/>
</Drawer.Navigator>
);
};
The answer might depend on what versions of react-navigation and react-navigation-drawer you are using. On a project using "react-navigation": "^4.0.10", and "react-navigation-drawer": "^2.3.3" this is what works for me:
.............
import { NavigationEvents, NavigationActions } from 'react-navigation';
export default class HomeScreen extends Component {
..........
constructor(props){
super(props)
this.state = {language: 'English', menuOpen: false};
}
...................
render(){
const { navigation } = this.props;
const setParamsAction = NavigationActions.setParams({
params: { isAdmin: this.state.isAdmin },
key: 'PointsScreen',
});
const setParamsTwo = NavigationActions.setParams({
params: { isAdmin: this.state.isAdmin },
key: 'OtherScreen',
});
return(
<View style={styles.container}>
<NavigationEvents
onDidBlur={payload => {this.setState({menuOpen: true})}}
onWillFocus={payload => {this.setState({menuOpen: false});
this.backHandler = BackHandler.addEventListener('hardwareBackPress', () =>
{
this.props.navigation.dispatch(setParamsAction);
this.props.navigation.dispatch(setParamsTwo);
this.props.navigation.navigate('PointsScreen');
return true;
})}}
/>
In this example I'm sending the info to other screens when I hit backhandler, but it works the same way for any other navigation event. So for example if you want to add this to your drawer open button you would just substitute this.props.navigation.openDrawer(); for this.props.navigation.navigate('PointsScreen');.
In other screens I have:
.............
render(){
const { navigation } = this.props;
const isAdmin = navigation.getParam('isAdmin') || '';
In the drawer screen I have:
render(){
const { navigation } = this.props;
const pointsProps = navigation.getChildNavigation('PointsScreen');
const isAdmin = pointsProps.getParam('isAdmin') || "";

passing ref from sibling

I am using the library react-native-dropdownaler and when I am creating the ref for it in App instead of adding the component in each screen I want to simply pass its ref to my Router and use it later.
the problem with passing its ref to the sibling is - they both render together so when I am passing the ref its still undefined
render() {
return (
<View style={styles.container}>
<StatusBar />
<Router alertRef={this.alertRef}/>
<DropdownAlert ref={ref => (this.alertRef = ref)} />
</View>
);
}
You can use the createRef API to create a ref. The current property will still not be set until after the first render though.
class App extends React.Component {
alertRef = React.createRef();
render() {
return (
<View style={styles.container}>
<StatusBar />
<Router alertRef={this.alertRef} />
<DropdownAlert ref={this.alertRef} />
</View>
);
}
}
I'd pass down the component itself instead and mirror the method in the component:
render() {
return (
<View style={styles.container}>
<StatusBar />
<Router alertRef={this}/>
<DropdownAlert ref={ref => (this.alertRef = ref)} />
</View>
);
}
alertWithType(type, title, message) {
this.alertRef.alertWithType(type, title, message);
}
The solution I end up with is :
class App extends Component {
constructor(props)
super(props)
this.state = {alertRef:null}
componentDidMount() {
this.setState({alertRef:this.alertRef})
}
render() {
return (
<View style={styles.container}>
<StatusBar />
{this.state.alertRef && (
<Router
alertRef={this.state.alertRef}
language={this.props.language}
/>
)}
<DropdownAlert ref={ref => (this.alertRef = ref)} />
</View>
);
}
}

How to pass a value to modal and show modal when click on flatlist item in react native

i want to pass a value from activity screen to modal screen. I am trying to open a screen when click on flatlist item an dpass value of item to modal,but it shows my detail before rendering modal screen,Here is my activity screen:-
<FlatList
data={this.state.myListDataSource}
renderItem={this._renderItem}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
keyExtractor={({item,index}) => item+index}
refreshControl={
<RefreshControl
refreshing={this.state.isRefreshing}
onRefresh={this.pullToRefresh}
/>
}
/>
<ListProducts
modalVisibility={this.state.listModalVisibility}
closeModal={() =>
this.setState({listModalVisibility:false})}
listName={this.state.listName}
listId={this.state.listId}
/>
handleListItemPress = (item) => {
this.setState({
listModalVisibility:true,
listName : item.name,
listId : item.list_id
})
showMessage('List Item : '+item.listId)
}
_renderItem = ({item}) => {
return(
<TouchableOpacity onPress={() => this.handleListItemPress(item)}>
<View >
<View>
<View style={{flexDirection:'row',marginBottom:2}}>
<ImageView
image={item.pictures[0]}
style={[{marginRight:2},styles.imageStyle]}
/>
<ImageView
image={item.pictures[1]}
style={[{marginLeft:2},styles.imageStyle]}
/>
</View>
<View style={{flexDirection:'row',marginTop:2}}>
<ImageView
style={[{marginRight:2},styles.imageStyle]}
image={item.pictures[2]}
/>
<ImageView
image={item.pictures[3]}
style={[{marginLeft:2},styles.imageStyle]}
/>
</View>
</View>
<View>
<TextViewNonClickable
textViewText={item.name}
/>
<TextViewNonClickable
textViewText={item.description}
/>
</View>
<Icon
name = 'more-vertical'
type = 'feather'
color = {color.colorWhite}
iconStyle={{padding:8}}
containerStyle = {{position:'absolute',top:8,right:8}}
onPress = {() => {
showMessage('Options')
}}
/>
</View>
</TouchableOpacity>
)}
This is my modal screen where i want to get list item id or name.But that screen shows details on the screen rather than rendering modal screen .
Here is my modal screen :-
export default class ListProducts extends Component {
constructor(props){
super(props)
this.state={
products : [],
refreshing : false,
listId : 256,
listName : props.name
}
}
_renderProducts = ({item}) => {
return(
<Product
image={item.image}
name={item.name}
price={item.price}
discountedPrice={item.discounted_price}
quantityAdded={item.quantity_added}
productId={item.product_id}
stock={item.stock}
/>
)
}
render() {
const {modalVisibility,closeModal,listName,listId} = this.props;
return (
<Modal
animationIn='bounceInRight'
animationOut='bounceOutRight'
isVisible={modalVisibility}
onBackButtonPress={closeModal}
>
<View style={{flex:1,backgroundColor:color.colorWhite}}>
<Header
placement='left'
leftComponent={
<FlatList
data={this.state.products}
renderItem={this._renderProducts}
keyExtractor={(item,index) => item+index}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this.pullToRefresh}
/>
}
numColumns={3}
style={{paddingLeft:2,paddingRight:2}}
/>
</View>
</Modal>
)
}
}
Step 1: pass props from modal to class.
In modal like:
this.props.setItem(“sunny”)
Step 2: Get that props in class in render method where modal initialised.
<ModalName SetItem={item => console.log(item)} \>
I'm actually using 'Dialog' from 'react-native-simple-dialogs' for popup. It works better for me than 'Modal', but i think the logic is the same.
Here is a simplified example of a edit email popup that works for me:
import React from 'react';
import { StyleSheet, View, TextInput } from 'react-native';
import { Button, Text } from 'native-base';
import { Dialog } from 'react-native-simple-dialogs';
export default class EditEmailPopup extends React.Component {
constructor(props) {
super(props);
this.state = {
isModalVisible: this.props.isModalVisible,
};
}
componentWillUpdate() {
this.state.isModalVisible = this.props.isModalVisible;
}
_updateEmailAndCloseDialog() {
// update some data...
this._onCloseDialog();
}
_onCloseDialog() {
this.setState({ isModalVisible: false});
this.props.client(); //this is a function transfered from parent that controls the visibility of the dialog.
}
render() {
return (
<View>
<Dialog
visible={this.state.isModalVisible}
onTouchOutside={() => this._onCloseDialog()}
>
<View>
<Text style={styles.text}>{'Update Email text'}</Text>
<View style={styles.popupButtons}>
<Button
transparent
style={styles.cancelButton}
onPress={() => this._onCloseDialog()}
>
<Text> {'cancel'} </Text>
</Button>
<Button
style={styles.okButton}
onPress={() => this._updateEmailAndCloseDialog()}
>
<Text> {'ok'} </Text>
</Button>
</View>
</View>
</Dialog>
</View>
);
}
}
Here is how i add my Dialog in the parent view:
{this.state.emailModalVisibility ? (
<EditEmailPopup
isModalVisible={this.state.emailModalVisibility}
client={this.afterClosePopup}
/>
) : null}
while this.state.emailModalVisibility initiated in the constructor in state as 'false'.
function written in parent:
_afterClosePopup = () => {
this.setState({
emailModalVisibility: false
});
};
and binded in the constructor so 'this' will belong to parent:
constructor(props) {
super(props);
this.afterClosePopup = this._afterClosePopup.bind(this);
this.state = {
emailModalVisibility: false
};
}

How to switch tabs from another component using react-native-scrollable-tab-view

Second day using React Native so I've no idea what I'm doing, but how do I switch tabs from within another component with react-native-scrollable-tab-view?
https://github.com/skv-headless/react-native-scrollable-tab-view
I have a MenuButton in a ButtonPage that I'm trying to switch tabs with using an onPress. However when I tap it I get:
undefined is not an object (evaluating 'this.props.tabView.goToPage')
What I've got is this
export default class Home extends Component {
render() {
return (
<View style={{flex: 1}}>
<StatusBar
barStyle='light-content'/>
<ScrollableTabView initialPage={1} renderTabBar={false}
ref={(tabView) => { this.tabView = tabView}}>
<FriendsPage tabView={this.tabView} tabLabel="Friends" />
<ButtonPage tabView={this.tabView} tabLabel="Button" />
<HangoutsPage tabView={this.tabView} tabLabel="Hangouts" />
</ScrollableTabView>
</View>
)
}
}
And in my ButtonPage I have this
export default class ButtonPage extends Component {
render() {
return (
<View style={styles.container}>
<View style={styles.buttonsContainer}>
<HangoutsButton/>
<View style={styles.spacer}/>
<MenuButton/>
</View>
</View>)
}
}
And that MenuButton is described by this
export default class MenuButton extends Component {
constructor(props) {
super(props)
this.goToPage = this.goToPage.bind(this)
}
goToPage(pageNumber) {
this.props.tabView.goToPage(pageNumber)
}
render() {
return (
<Indicator
position='left top'
value='3'
type='warning'>
<TouchableHighlight
onPress={() => this.goToPage(0)}
underlayColor='#ed8600'
style={styles.touchable}>
<Image source={require('./resources/menuicon.png')} style={styles.image} />
</TouchableHighlight>
</Indicator>
)
}
}
How do I get the reference for my scrollableTabView all the way down to my button so I can tap it and change the page with goToPage?
I assumed you could stick the object in a prop and pass that prop all the way down and then use the function goToPage on it from MenuButton.
You don't need to tabview ref all the way down. Just use
export default class MenuButton extends Component {
render() {
return (
<Indicator
position='left top'
value='3'
type='warning'>
<TouchableHighlight
onPress={() => this.props.onPress && this.props.onPress()}
underlayColor='#ed8600'
style={styles.touchable}>
<Image source={require('./resources/menuicon.png')} style={styles.image} />
</TouchableHighlight>
</Indicator>
)
}}
export default class ButtonPage extends Component {
render() {
return (
<View style={styles.container}>
<View style={styles.buttonsContainer}>
<HangoutsButton/>
<View style={styles.spacer}/>
<MenuButton onPress={ () => this.props.goToPage && this.props.goToPage() }/>
</View>
</View>)
}}
And finally
export default class Home extends Component {
goToPage(pageId) {
this.tabView.goToPage(pageId);
}
render() {
return (
<View style={{flex: 1}}>
<StatusBar
barStyle='light-content'/>
<ScrollableTabView initialPage={1} renderTabBar={false}
ref={(tabView) => { this.tabView = tabView}}>
<FriendsPage tabView={this.tabView} tabLabel="Friends" />
<ButtonPage tabView={this.tabView} tabLabel="Button" goToPage={ () => this.goToPage(1) } />
<HangoutsPage tabView={this.tabView} tabLabel="Hangouts" />
</ScrollableTabView>
</View>
)
}
}

Categories

Resources