So i have a Drawer.Js using 'react-native-off-canvas-menu' where the sole purpose is to open and close the drawer. The problem is that this drawer will only open and close with gesture (slide left/right). I want to bind this open and close function with a button. The problem is it shows an error when i try to call function handleClick from Home.Js to my Drawer.Js
Inside my Drawer.Js
class FirstScreen extends Component {
constructor(props) {
super(props);
this.state = {
menuOpen: false
};
this.handleClick = this.handleMenu.bind(this);
}
handleMenu() {
const { menuOpen } = this.state;
this.setState({
menuOpen: !menuOpen
});
}
// Some Render Method Where i tried to create a button, and calling
this.handleMenu() on the onPress event, and it's successful
*//After the Render Method
export function a() {
return this.handleClick();
}
I am also using react native router flux which the first route of my apps is going to Home.js, where in Home.js i am going to put a button to trigger the drawer to open.
Here's my code for Home.js
*//Some Import
import { a } from './Drawer';
class Home extends Component {
constructor(props) {
super(props);
this.handleKlik = this.handleKlik.bind(this);
}
handleKlik() {
a();
}
*// Render Method Start
<View>
<TouchableOpacity onPress={() => this.handleKlik()}>
<View style={styles.btnContainer}>
<Text style={styles.btnText}>{'Toggle'.toUpperCase()}
</Text>
</View>
</TouchableOpacity>
<View>
Well here in Home.js, when i tried to click the button, i received and error like 'undefined is not a function (evaluting 'this.handleClick')'.
Well i think i know the problem where my export function is probably the problem. Can anyone please elaborate on how can i fix this? i've read the tutorial and i can't seem to understand why it's so hard to call a function inside another Js Files in my project
Related
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'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>
);
}
}
I've been trying to call a function which is in a screen of a navigator from its screen.
To clarify the point, here is a snippet of my code...
//ScreenA.js
export default class ScreenA extends React.Component {
showWarning(){
this.setState({showWarning: true});
setTimeout(function() {
this.setState({showWarning: false});
}.bind(this), 3000);
}
render() {
return (
<View style={{backgroundColor : this.state.showWarning ? "#red" : "#blue"}}>
{this.state.showWarning && <Warning />}
</View>
)
}
}
//Nagigator.js
default export const Navigator = StackNavigator({
ScreenA: {screen: ScreenA},
ScreenB: {screen: ScreenB},
});
//App.js
export default class App extends React.Component {
handleSubmit(qrCode){
if(qrCodeIsInvalid){
this.navigator.ScreenA.showWarning();
//This is just a sudo code.
//How do we call ScreenA.showWarning here?
}
}
render() {
let props = {/*some props here*/};
return (//This "ref" stops the application without describing any reason
<Navigator screenProps={props} ref={nav => { this.navigator = nav; }}/>
);
}
}
There is an example of how to call a function from a navigation header, but not from the class which exports the navigator.
I thought that each screen can be accessed via ref, but this causes an error without explaining what's happening.
Has anyone encountered a similar situation?
Any advice will be appreciated.
P.S.
# Nimrod Argov
Here are details of what I've been trying to achieve.
ScreenA has a QR code reader and submit function, which submits QR codes to App.js.
App.js has handleSubmit function, where submitted QR codes are sent to a server and labelled as either valid or invalid.
If a submitted QR code turns out to be invalid, ScreenA has to show a warning message and change its background colour for 3 seconds.
It might be achieved by having App.js pass a prop {showWarning:true} to ScreenA and pass {showWarning:false} in 3 seconds.
However, I thought it would be ScreenA's responsibility to change its background colour. Thus, I set setTimeout and setState in the showWarning().
I did it this way:
ScreenA.js
While navigate to ScreenB, including the function you want to call.
export default class ScreenA extends React.Component {
constructor(props) {
super(props);
this.doSomething = this.doSomething.bind(this);
}
doSomething() {
this.setState({blah: true});
}
navigateToB() {
this.props.navigation.navigate('ScreenB', {
doSomething: this.doSomething,
});
}
}
ScreenB.js
So you can do this in ScreenB.
const { state, setParams, navigate } = this.props.navigation;
const params = state.params || {};
params.doSomething();
I use react navigation. I have a TabNavigator. Each Tab contains a StackNavigator. From one StackNavigator, it is possible to open a Modal.
The Modal is opened when I click on a Button in a certain Component.
export default class CallModalComponent extends Component {
constructor(props) {
super(props)
...
}
...
render() {
const { navigate } = this.props.navigation;
return (
<Button
....
onPress={() => navigate("Modal")}/>
The in the TabNav registered screen <MyModal /> is a stateful Component.
On close of the Modal I need the state of <MyModal /> to be passed down to <CallModalComponent />.
The problem I am having is how that might work with react navigation in between... I know that I can use redux and send/retrieve it through the global store. But I wonder if its possible with only react native.
Any suggestions?
EDIT
I implemented the Code from answer
export default class CallModalComponent extends Component {
constructor(props) {
super(props)
...
}
...
onModalDismis(childVar) {
console.log('modal is closing');
console.log(childVar);
}
render() {
const { navigate } = this.props.navigation;
return (
<Button
....
onPress={(childVar) => navigate("Modal", {onModalDismis: this.onModalDismis()})}/>
// Then in your modal component
componentWillUnmount () {
console.log('unmount');
this.props.navigation.state.params.onModalDismis('here we go');
}
The following gets logged:
When the Modal Component is mounted I get:
modal is closing
undefined
Then, when I actually close the Modal, I get:
unmount
and then the error:
Cannot read property of onModalDismiss of undefined.
I expected to be nothing logged on mounting of the Modal. And then, when I close the Modal I expected
unmount, modal is closing and here we go to be logged.
You can pass parameters to screens while navigating. This allows you to send a function to next screen and then you can initiate it when you want. More detail here.
Example
export default class CallModalComponent extends Component {
constructor(props) {
super(props)
...
}
...
onModalDismis() {
console.log('modal is closing');
}
render() {
const { navigate } = this.props.navigation;
return (
<Button
....
onPress={() => navigate("Modal", {onModalDismis: this.onModalDismis})}/>
// Then in your modal component
componentWillUnmount () {
this.props.navigation.state.params.onModalDismis();
}
#bennygenel was very close. Added a little.
export default class CallModalComponent extends Component {
constructor(props) {
super(props)
...
}
...
onModalDismis(childVar) {
console.log('modal is closing');
console.log(childVar);
}
render() {
const { navigate } = this.props.navigation;
return (
<Button
....
onPress={() => navigate("Modal", {onModalDismis:(childVar) => this.onModalDismis(childVar)})}/>
// Then in your modal component
componentWillUnmount () {
this.props.navigation.state.params.onModalDismis("some var");
}
The reason for using an arrow function is because it binds() the context of this https://medium.freecodecamp.org/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56 and it only gets executed when onModalDismis() is called, and not the render of <CallModalComponent/>. Difference in using functions in react-native
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);
}