I'm trying to wrap a button that already exists with the functionality of recordActivityTag. Right now the way it is working it is not capturing the function of the data from the first button. I need to follow tags throughout the app. That's why I've constructed recordActivityTag. That functionality works fine for events, except for buttons.
How do I call within the onPress - if that's possible - the action on a button from another screen? I know I need to pass in the outer prop into TouchableOpacity and then call the other button.
import * as React from "react";
import { Core } from "common";
import { TouchableOpacity } from "react-native";
interface BtnProps {
readonly data: string
readonly recordActivityTag:(tag: Core.ActivityTag) => void
}
export default class Button extends React.Component<BtnProps, {}> {
constructor(props: BtnProps) {
super(props);
}
render() {
const { recordActivityTag } = this.props;
return (
<TouchableOpacity>
onPress {() => recordActivityTag}
{this.props.children}
</TouchableOpacity>
);
}
}
Make sure that you give your function to the onPress prop of the TouchableOpacity component, and that you actually call recordActivityTag within it.
export default class Button extends React.Component<BtnProps, {}> {
render() {
const { recordActivityTag } = this.props;
return (
<TouchableOpacity onPress={() => recordActivityTag()}>
{this.props.children}
</TouchableOpacity>
);
}
}
Related
How to solve this? I have a custom Button component that gets included in my ModalScreen. It all seems to work but the onPress function is acting up. It seems to have lost the scope for some reason so I can't reference this or even add params to the function. What am I missing here?
import React from 'react';
import {
Text,
View,
} from 'react-native';
import Styles from 'app/constants/Styles';
import Button from 'app/components/Button';
export default class ModalScreen extends React.Component {
onBtnPress() {
console.log('dfsdfsdf'); /// << this gets consoled out just fine
//this.props.navigation.navigate('Main'); <<<< this won't work
}
render() {
return (
<View style={Styles.center}>
<Text>MOdalScreen</Text>
<Button label='Gå vidare' onPress={ this.onBtnPress }/>
</View>
);
}
}
Button.js
import React, { Component } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import Styles from 'app/constants/Styles'
import Vars from 'app/constants/Vars'
export default class Button extends Component {
render() {
return (
<TouchableOpacity style={[Styles.round, Styles.primaryBackground]} onPress={this.props.onPress}>
<Text style={[Styles.label, Styles.textCenter, { margin: Vars.spacing.narrow }]}>
{this.props.label}
</Text>
</TouchableOpacity>
)
}
}
You're right that it's lost the scope. You just need to bind the scope to the handle function somehow before you give it to the Button component. One popular way is with a handy arrow function:
<Button label='Gå vidare' onPress={ () => this.onBtnPress() }/>
Or you could use bind in the constuctor:
export default class ModalScreen extends React.Component {
constructor(props) {
super(props);
this.onBtnPress = this.onBtnPress.bind(this)
}
onBtnPress() {
console.log('dfsdfsdf'); /// << this gets consoled out just fine
//this.props.navigation.navigate('Main'); <<<< this won't work
}
I am a beginner in the react-native framework. I am building an sample mobile application. And I am stuck at the very basic step.
I am trying to call 'getBusinessNews()' function on click event, which will return a component. But due to some reason, it's not returning.
I have doubled checked the path of the component and its correct.
Even the console.log defined inside the function is getting displayed.
I am attaching the code, all kind of help is appreciated.
Thank you in advance.
import React, {Component} from 'react';
import {Text,View,TouchableOpacity} from 'react-native';
import BusinessNews from '../News/BusinessNews';
class categories extends Component{
render(){
return(
<View>
<TouchableOpacity onPress={this.getBusinessNews.bind(this)}>
<Text>Business News</Text>
</TouchableOpacity>
</View>
);
}
getBusinessNews(){
console.log(1);
return(
<BusinessNews />
);
}
export default categories;
Returning component from event handler/listener to render will not work.
Instead do state update to decide whether component BusinessNews will render or not.
Its should do like this.
constructor
constructor() {
this.state = {
showBusiness: false//initially set to false
}
}
getBusinessNews
getBusinessNews() {
this.setState({showBusiness: true})//set to true to show BusinessNews
}
render
render() {
render() {
return (
<View>
<TouchableOpacity
onPress={this
.getBusinessNews
.bind(this)}>
{this.state.showBusiness ===true && <BusinessNews/>}//check boolean true
<Text>Business News</Text>
</TouchableOpacity>
</View>
);
}
}
You can return a component on click. As you have to returns component in render() only. You need to change the logic to render component.
You can call <BusinessNews /> in somewhere in render() to add component.
I have a screen inside my react-navigation StackNavigator that looks like this:
import React from 'react';
import { FlatList, ScrollView, StyleSheet, Text, View } from 'react-native';
import { List, ListItem } from 'react-native-elements';
import Accordion from '#ercpereda/react-native-accordion';
export default class PassportScreen extends React.Component {
static navigationOptions = {
title: 'Passport Recovery',
};
constructor(props) {
super(props);
this.renderItem = this.renderItem.bind(this);
}
renderItem(item) {
return (
<View>
<Accordion
header={item.item.key}
content={item.item.content}
/>
</View>
)
}
render() {
const instructions = [
{
key: <Text>1. Fill out a passport application form</Text>,
content: <Text>Content</Text>
},
{
key: <Text>2. Fill out a lost/missing passport statement</Text>,
content: <Text>Content</Text>
},
///...etc
];
return (
<ScrollView>
<FlatList
data={instructions}
renderItem={this.renderItem}
/>
</ScrollView>
)
}
}
module.exports = PassportScreen;
however, when I click to navigate to this screen from another screen, I get this error: TypeError: this.props.header is not a function. (In 'this.props.header({
isOpen: this.state.is_visible
})', 'this.props.header' is an instance of Object).
Other questions I've looked at with similar errors have mentioned passing props to the constructor and needing to pass this.renderItem instead of this.renderItem(), both of which I have already done, so I'm wondering if the problem comes from the fact that this screen is inside a StackNavigator and is navigated to by clicking on a ListItem. Is my intuition correct? If so, how can I fix this?
It seems that the header prop accepts a function, rather than just a component like content does.
Right now you're directly passing an object to the header prop, therefore it won't accept the callback function.
You may try the following approach in order to pass a callback to the header.
PassportScreen.js
customFunc = (callback) => {
console.log(callback)
}
renderItem = (item) => { // Useful to bind `this`
return (
<View>
<Accordion
header={this.customFunc}
content={item.item.content}
/>
</View>
)
}
ChildComponent.js
this.props.header('I'm setting the callback here')
I am trying to load my parent component from child component on button press. But it's not rendering the parent components from btnPress method. I am not getting any error.
onButtonPress
<Button onPress={() => btnPress(parent_id, id)}>
<Icon name="arrow-forward" />
</Button>
btnPress Function
function btnPress(parent_id, id) {
const App = () => (
//I have tried this way but this didn't work. No any error, i can see log on console
<Container>
<Headerc headerText={'Fitness sdaf'} />
<ExerciseList pId={parent_id} mId={id} />
</Container>
);
console.log(id);
AppRegistry.registerComponent('weightTraining', () => App);
}
full code(child component)
import React from 'react';
import { Right, Body, Thumbnail, Container, ListItem, Text, Icon } from 'native-base';
import { AppRegistry
} from 'react-native';
import Headerc from './headerc';
import ExerciseList from './exerciseList';
import Button from './Button';
const ExerciseDetail = ({ exercise }) => {
const { menu_name, menu_icon, parent_id, id } = exercise;
function NumberDescriber() {
let description;
if (menu_icon === 'noimg.jpg') {
description = `http://www.xxxxxx.com/uploads/icons/${menu_icon}`;
} else if (menu_icon === 'noimg.jpg') {
description = menu_icon;
} else {
description = `http://www.xxxxx.com/uploads/icons/${menu_icon}`;
}
return description;
}
function btnPress(parent_id, id) {
const App = () => (
<Container>
<Headerc headerText={'Fitness sdaf'} />
<ExerciseList pId={parent_id} mId={id} />
</Container>
);
console.log('-------------------------------');
console.log(id);
console.log('+++++++++++++++++++++++++++');
AppRegistry.registerComponent('weightTraining', () => App);
}
return (
<ListItem>
<Thumbnail square size={80} source={{ uri: NumberDescriber() }} />
<Body>
<Text>{menu_name}</Text>
<Text note> {menu_name} exercise lists</Text>
</Body>
<Right>
<Button onPress={() => btnPress(parent_id, id)}>
<Icon name="arrow-forward" />
</Button>
</Right>
</ListItem>
);
};
export default ExerciseDetail;
Please do let me know, if you need more information.
I would not suggest doing that way, it look totally anti-pattern and not.
better try with navigation or create a pattern like this
inside your index.js or index.android.js or index.ios.js
import App from './App' //your app level file
AppRegistry.registerComponent('weightTraining', () => App);
now in your app js file
export default App class extends React.Component{
constructor(props){
super(props);
this.state ={
component1:false,
component2:true,
}
}
btnPressed =()=>{
//handle state update logic here
}
render(){
if(this.state.component1) return <Component1/>
return <Component2/>
}
}
**** not the best solution available, play around and you will get best
To navigate from this component to your parent component unless you want to implement your own navigation which isn't recommended, you should look into one that's already built and adopted by many in the react-native ecosystem.
Some of the biggest ones:
React Native Navigation
React Navigation
React Native Router
I personally highly recommend option number 1, since it seems to be the most production tested and production ready implementation out there
I am trying to create a loading screen in React Native that will navigate to a confirmation screen once the time from a setTimeout function has been fulfilled. Currently, the screen loads, but does not navigate to the confirmation screen after the setTimeout interval.
import React from 'react';
import { Text, View, Image } from 'react-native';
import { Actions as NavigationActions } from 'react-native-router-
flux';
import styles from './styles';
export default class ProcessingLoader extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
setTimeout(this.navigateToConfirmation, 3000);
}
navigateToConfirmation() {
NavigationActions.checkoutConfirmation({ product: this.props.product, type: 'reset' });
}
renderLoader() {
return (
<View style={styles.textContainer}>
<Text style={styles.loaderText}>Processing Order ...</Text>
</View>
);
}
render() {
return (
<View style={{ flex: 1 }}>
{this.renderLoader()}
</View>
);
}
}
I've tried using setTimeout in componentDidMount as well as in render. I've also tried using and arrow function vs not using an arrow function. Am I utilizing setTimeout completely wrong here? I'm afraid that I don't understand why it will not navigate to the next screen after 3 seconds. Thanks in advance!
You are not invoking the function, use parenthesis to do that.
Also, the first parameter is a callback, so put your invokation inside a function, like this:
componentDidMount() {
setTimeout(function(t){t.navigateToConfirmation()}, 3000, this);
}
or in an arrow function:
componentDidMount() {
setTimeout(() => {this.navigateToConfirmation()}, 3000);
}