React Native - OnPress button not working - react-native

I have a button with a onPress event i am trying to simply console log that the button was successfully pressed.
The button is within my template file i have extracted this portion of code to a separate file, ive done the same for my tyles.
The add() function associated with the press does not fire when i press the add button, so the console.log does not show.
But the console.log does does show on initial load of the screen ( i dont know why this is )
items.screen.js
import React, { Component } from 'react';
import { StyleSheet, Text, View, TextInput } from 'react-native';
import style from './items.style'
import template from './items.template';
export default class ItemsScreen extends Component {
static navigationOptions = {
title: "Items"
}
constructor(props) {
super(props);
this.state = { text: '' };
}
add() {
console.log("pressed add button");
}
render() {
return template(this, style);
}
}
items.template.js
import React, { Component } from 'react';
import { Text, View, TextInput, Button } from 'react-native';
import { style } from './items.style'
export default (template, style) => {
return (
<View style={style.container}>
<TextInput
style={{ width: 300 }}
value={template.state.text}
onChangeText={(text) => template.setState({ text })}
/>
<Button
onPress={template.add()}
title="Add"
/>
</View>
);
}

You are not assigning template.add to the on press event, instead your code is executing the add function and attempting to assign the result of that to the onPress event.
I find the following two options to be cleaner than the other suggestions:
Create a local onPress Handler (in items.template)
onPress = () => {
template.add();
}
and then
onPress={this.onPress} //note the lack of parentheses `()`
or
create an inline function
onPress={() => template.add()}

You should pass function in attribute,not function call, so it should be
<Button
onPress={template.add.bind(template)}
title="Add"
/>

Related

React call function and setstate when go back to a previous screen

I'm new in React's world
I have 2 screens : Stock and Barcode.
In Stock, i navigate to Barcode's screen.
When i scan a barcode, i go back to the previous screen I would like to set the input text with the barcode and call a function. In my example joinData();
The problem is to set the input text and call a function.
I tried examples and answers but i don't find or don't understand how to to that.
I tried something in componentDidUpdate() but it fails
Invariant Violation:Maximum update depth exceeded
Stock.js
import React, {useState} from "react";
import { ScrollView, TouchableWithoutFeedback, Dimensions, StyleSheet, FlatList, View, Alert, TouchableOpacity, TextInput } from 'react-native';
//galio
import { Block, Text, theme } from "galio-framework";
import { Button, Icon, Input } from "../components/";
export default class Stock extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
this.array = [];
this.state = {
arrayHolder: [],
Input_ITMREF: ''
};
}
// I tried this but it fails
componentDidUpdate() {
if (this.props.navigation.getParam('itmref') != 'undefined') {
this.setState({ Input_ITMREF: this.props.navigation.getParam('itmref')});
}
}
componentDidMount() {
this.setState({ arrayHolder: [...this.array] }) // RafraƮchit la liste
}
joinData = () => {
vxml = this.state.Input_ITMREF+" I do something";
}
Render() {
return (
<Block flex>
<Block row space="evenly">
<Block center>
<Input
placeholder='Code article'
onChangeText={data => this.setState({ Input_ITMREF: data })}
ref={this.myRef}
/>
</Block>
</Block>
<Block center>
<Button style={styles.button} onPress={() => this.props.navigation.navigate('Barcode')}>Barcode</Button>
<Text style={{ margin: 10 }}>Post: {this.props.navigation.getParam('itmref')}</Text>
</Block>
</Block>
);
}
}
And Barcode.js
import React, {} from 'react';
import { ScrollView, TouchableWithoutFeedback, Dimensions, StyleSheet, FlatList, View, Alert, TouchableOpacity, TextInput } from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
import { Button } from "../components/";
export default class Barcode extends React.Component {
static navigationOptions = {
header: null //hide the header bar
};
handleBarCodeScanned = ({ type, data }) => {
this.props.navigation.navigate("Stock", {
itmref: data
});
};
render() {
return (
<BarCodeScanner
onBarCodeScanned={this.handleBarCodeScanned}
style={styles.barcodeScanner}
/>
);
}
}
You can pass a state handler function as prop to Barcode screen and use that to set value for textInput in state.
in Stock(in state)
state = {
inputValue: ''
}
....
const setInputTextValue= (newValue) => {
this.setState({
inputValue: newValue
})
you pass this function as prop to Barcode scene and call it whenever you wanna set a new value(considering Stock scene is still mounted).
UPDATE: What is the proper way to update a previous StackNavigator screen?
also another solution i just saw: Updating State of Another Screen in React Navigation
You need to use WillFocus method(Included in react-navigation) when you comeback from Barcodepage to stockPage
componentDidMount(){
console.log("willFocus runs") initial start
const {navigation} = this.props;
navigation.addListener ('willFocus', async () =>{
console.log("willFocus runs") // calling it here to make sure it is logged at every time screen is focused after initial start
});
}
For More Information read this document
https://reactnavigation.org/docs/function-after-focusing-screen/

creating a TextInput component that can output normal and output a ****/ secureTextEntry={true}

So I have a problem creating a text input component just like when IGNITE CLI created a component named RoundedButton (code shown below). I want to create a similar component but a TextInput that can output a normal output and output a **** character whenever pressed and needed with simple tweaking. How can I do this?
This is the code for RoundedButton :
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { TouchableOpacity, Text } from 'react-native'
import styles from './Styles/RoundedButtonStyles'
import ExamplesRegistry from '../Services/ExamplesRegistry'
// Note that this file (App/Components/RoundedButton) needs to be
// imported in your app somewhere, otherwise your component won't be
// compiled and added to the examples dev screen.
// Ignore in coverage report
/* istanbul ignore next */
ExamplesRegistry.addComponentExample('Rounded Button', () =>
<RoundedButton
text='real buttons have curves'
onPress={() => window.alert('Rounded Button Pressed!')}
/>
)
export default class RoundedButton extends Component {
static propTypes = {
onPress: PropTypes.func,
text: PropTypes.string,
children: PropTypes.string,
navigator: PropTypes.object
}
getText () {
const buttonText = this.props.text || this.props.children || ''
return buttonText.toUpperCase()
}
render () {
return (
<TouchableOpacity style={styles.button} onPress={this.props.onPress}>
<Text style={styles.buttonText}>{this.getText()}</Text>
</TouchableOpacity>
)
}
}
Have the secureTextEntry linked to component state/prop and change it on button press.
So like this:
secureTextEntry={this.state.showDots}
and then onPress of button
onPress = () => {
this.setState({ showDots: true/false})
}

React-Native, ActionSheetIOS display instead of Picker

I would like to use the ActionSheetIOS on iOS, instead of the native picker wheel.
My app crashes out, how can I display my component?
Here is my Picker component:
// Picker.ios.js
import React, { Component } from "react";
import { StyleSheet, ActionSheetIOS, View } from "react-native";
const PickerList = props => {
const { label, options, selectedValue, name, onChange, identifier } = props;
return ActionSheetIOS.showActionSheetWithOptions(
{
options: options,
cancelButtonIndex: 1,
destructiveButtonIndex: 2
},
optionIndex => {
console.log('clicked')
}
);
};
export default PickerList;
I'm using conditional rendering to display my pickers, and a platform specific import:
import Picker from "./common/Picker";
{setYear
? <Picker
selectedValue={setGroup}
label="Year group"
onChange={this.onGroupChange}
options={
categories.find(category => {
return category.id == setYear;
}).options
}
/>
: null}
ActionSheetIOS only shows the options, you have to have some view component to replace the picker in the view. I used TouchableOpacity ja ActionSheetIOS to replace Picker on IOS like this:
<TouchableOpacity onPress={this.onSelectCategory.bind(this)}>
<Text style={styles.textInputStyle}>
{this.state.category}
</Text>
</TouchableOpacity>
onSelectCategory() {
ActionSheetIOS.showActionSheetWithOptions(
{ options: FEEDBACK_CATEGORIES},
(buttonIndex) => this.setState({ category: FEEDBACK_CATEGORIES[buttonIndex] }));
}
I use this.state.category to show my selection in TouchableOpacity
When user press the TouchableOpacity the ActionSheetIOS is shown
When user select option the callback function is called and I update the
selected index to the this.state.category

FlatList renderItem is firing, console.logs are visible, but text is not. What happened to the text?

I have a harcoded a JSON object just to make sure that the items inside the FlatList will be rendered properly. I can read all of the console.logs I wrote inside, but none of the Text is appearing. Any ideas why?
here is the code:
import {
View,
FlatList,
Text,
TouchableWithoutFeedback,
AsyncStorage,
ScrollView,
Picker
} from 'react-native'
import { NavigationActions } from 'react-navigation';
import { Header, Card, CardSection, Button, Input } from '../common';
import Config from '../Config';
export default class CustomStore extends Component {
constructor(props) {
super(props);
this.state = {
stores: [],
forceRedraw: false
};
}
static defaultProps = {
//stores:[{"place": "youngja", "id": "1"},{"place": "tasty", "id": "2"}]
};
componentWillMount() {
const newJSON = {"gym":{"id":"1", "day": "Sunday"}, "restaurant":{"id": "2", "day": "Monday"}};
const JSArr = Object.values(newJSON);
//console.log(JSArr);
this.setState({
stores: JSArr
});
}
deleteEntry() {
console.log('this is working')
}
renderListOfStores() {
return <FlatList
data={this.state.stores}
renderItem={ (item) => {
console.log('here is your thing',item);
this.singleStore(item)}
}
keyExtractor={(item) => item.id}
/>;
}
singleStore(item) {
return <View>
{console.log('inside the singleStore method')}
<Card>
<Text>hello{console.log('this is inside the text tag')}{item.day}</Text>
<Button
onPress={() => this.deleteEntry()}
>
<Text>Press this to delete this entry</Text>
</Button>
</Card>
</View>;
}
render() {
return(
<ScrollView>
<Header headerText="Custom Store Screen"/>
<Text>This should be a list of stores</Text>
{this.renderListOfStores()}
<Text>This is the end of the list</Text>
</ScrollView>
)
}
}
As you can see, I've put console.logs inside the renderListOfStores method to verify that it's being fired. I have another console.log inside the singleStore method..this console log is also visible..as is the last console log inside the tag. No idea why I'm able to read console.logs, but none of the text
you need to put return before this.singleStore() inside your renderItem props.

Keyboard listener is running more then once

Hey I'm trying to create an event that will fire when the keyboard shows up but the function is firing more then once, I don't know why ..
import React, { Component } from 'react';
import { Keyboard, Alert, View, TextInput } from 'react-native';
export default class App extends Component {
constructor(props: any) {
super(props);
this.kbDidShowListener = Keyboard.addListener('keyboardDidShow', () => Alert.alert('keyboard is up'));
}
componentWillUnmount() {
this.kbDidShowListener.remove();
}
render() {
return (
<View style={{ marginTop: 30 }}>
<TextInput />
</View>
);
}
}
here is an expo for the example (you will see the alert more then once)
https://snack.expo.io/H1DHaIdgM
p.s I'm working on Android.
thanks!
The render function does not run only once. Usually refreshes multiple times too, while calculating the state and props. That could explain the issue.
If you want to be sure, try adding a console too inside the render method, to see if the numbers match.
Actually, another thing I am thinking. Try moving the code to the componentWillMount or componentDidMount
componentDidMount(){
this.kbDidShowListener = Keyboard.addListener('keyboardDidShow', () => Alert.alert('keyboard is up'));
}