react native onPress and props - react-native

On react native, why can I call the return function to pass a prop, but when passing it in a composed function it won't work?
This works
const pop = props.onPress;
...
<TouchableOpacity style={styles.okButton} onPress={pop}>
But,
function closee() {
console.log('aaadsedf');
props.onPress;
}
...
<TouchableOpacity style={styles.okButton} onPress={closee}>
shows log working ok, but doesnt trigger the props.onPress
So how to properly call the onPress?
how to properly pass the composed function?

You need to call it like:
function closee() {
console.log('aaadsedf');
props.onPress();
}

Related

React Native doesn't re-render on DOM change

I had an array of components inside a ScrollView component. Somehow react native doesn't re-render when the array is modified.
Here's a demonstration of my problem:
const TestApp = () => {
const [arr, setArr] = useState([]);
function pushArr() {
setArr((arr) => {
arr.push(1);
return arr;
});
console.log('pushArr():', arr);
}
function flushArr() {
setArr([]);
console.log('flushArr():', arr);
}
useEffect(() => {
console.log('useEffect():' , arr);
})
return (
<>
<ScrollView style={{flex:1}}>
{arr.map((elem, i) => <Text key={i}>{elem}</Text>)}
</ScrollView>
<Button title="Push" onPress={pushArr}></Button>
<Button title="Flush" onPress={flushArr}></Button>
</>
)
}
The page remains blank, and no updates happen on button press.
I've logged out arr and these are my findings:
pushArr() and flushArr() works as expected
useEffect() gets triggered only on startup and after flushArr()
Can anyone explain this behavior, and what mistakes have I made?
If I remember correctly, you need to make a copy of the array whenever you want it to “react”. The new memory address will let react know it should update. In other words, you shouldn’t mutate the array.
You can use the spread operator to make a copy and then push an element to the end which you can then pass to useArr. Usually I see people just passing the new object inside your useArr function.
I also don’t see you passing anything to your useArr function.

what is the difference between passing an object with a variable and a lone variable to a react native component?

My lack of success in this problem may be due to a lack of proper terminology when Googling it but nonetheless I am completely stumped. I am passing an onPress function to a custom component in react native. When I pass it by itself as:
export const AddMorePlants = ( onPress ) => {
return (
<TouchableHighlight
onPress={onPress}>
.
.
.
}
I get a this2.props.onPress is not a function error but when I have the exact same code except with the onPress passed within curly braces:
export const AddMorePlants = ({ onPress }) => {
return (
<TouchableHighlight
onPress={onPress}>
.
.
.
}
It Works!
Why does the second one work and not the first?
Sorry for a kind of basic question I just have been really Googling and cant figure it out. Thanks in advance and I can provide any more info if needed.
A functional component in React only has one parameter. The props. You can read more about it here
So what your first attempt at passing the onPress function actually looks like is:
export const AddMorePlants = (props) => {
return (
<TouchableHighlight onPress={props}/>
);
}
When the TouchableOpacity tries to execute the method, it hits the is not a function error because props is an object.
When you do:
export const AddMorePlants = ({onPress}) => {
return (
<TouchableHighlight onPress={onPress}/>
);
}
what you are doing is something called destructuring assignment and it's equivalent of doing:
export const AddMorePlants = (props) => {
const {onPress} = props;
return (
<TouchableHighlight onPress={onPress}/>
);
}
By putting the brackets inside the parentheses you are just doing a shorthand version of this destructuring assignment that we have mentioned.
Here's another version that would also work:
export const AddMorePlants = (props) => {
return (
<TouchableHighlight onPress={props.onPress}/>
);
}
As you can see there are many ways to access an object's property.
The important part is to remember that the props object is the only parameter passed into a functional component.
I hope this helps you understand what's going on there.
In the first function you need to pass only one param i.e onPress to your component while in second you are destructuring assignment so you are doing something like onPress = this.props.onPress and passing an object of params.

Query in react native about sliding up panel

In React Native iOS, I would like to slide in and out of a like in the following picture.
So I installed this https://github.com/octopitus/rn-sliding-up-panel for ease.
but this error is showing =>
i cant understand whats wrong, I am new to react native. Please Help!
You cannot access variable called _panel from this object because you are inside a function itself. besides you are using function based react, in order to create a reference check useRef() hook or switch to class based component and then you can use this._panel;
smthg like this:
function AccessingElement() {
const elementRef = useRef();
const onPress = () => {
// e.g
elementRef.current.show();
}
return (
<View ref={elementRef}>
...child views
</View>
);
}

Check if navigation.navigate is called in react native testing

I've been using 'react-test-renderer' for testing react-native, Mostly on it's functions. Lately I've found out that there is a testing library for react-native which is #testing-library/react-native. What I wanted to do is to check if navigation.navigate or alert has been called in a function. I don't know which of these libraries can achieve that and how.
onSubmitPress = () => {
if (true) {
this.props.navigation.navigate('MainPage');
else {
showAlert( "Not Allowed);
}
You can use 'react-test-renderer':
like this:
const fakeNavigation = {
navigate: jest.fn(),
};
const tree = renderer.create(
<YourComponent navigation={fakeNavigation} />
);
after that you can use jest expect function to test if mock navigation.navigate is called someThing like this:
const instance = tree.getInstance();
instance.onSubmit();
expect(fakeNavigation.navigate).toBeCalledWith('MainPage')
for react-native-testing-library it's a bit different as you test mostly what user sees depending of the behavior of your component.
Basically you look for your button that calls onSubmit and then use fireEvent from react-native-testing-library to press it, after that you expect the text of your alert to be shown in screen or not.
If you have a button like this in your component=
<TouchableOpacity onPress={onSubmit}>
<Text>Submit</Text>
</TouchableOpacity>
You can test the behavior of you function like this:
const {getByText} = render(<YourComponent/>)
let buttonText = getByText('Submit');
fireEvent(buttonText.parent, 'press'); //parent to get to TouchableOpacity
alertText = getByText('Not Allowed');
expect(alertText).toBeDefined();

React Native onPress being called automatically

I am having trouble with react-native onPress Feature. The onPress should only work when it is actually been triggered by a touch event (i suppose) , that is when i press the button on the screen. But it seems the onPress gets triggered itself when the render function is called. When i try to press manually, it doesn't work.
import React, { Component } from 'react';
import { PropTypes, Text, View ,Alert } from 'react-native';
import { Button } from 'react-native-material-design';
export default class Home extends Component {
render() {
return (
<View style={{flex:1}}>
<Button value="Contacts" raised={true} onPress={this.handleRoute('x')} />
<Button value="Contacts" raised={true} onPress={this.handleRoute('y')} />
<Button value="Contacts" raised={true} onPress={this.handleRoute('z')} />
</View>
);
}
handleRoute(route){
alert(route) // >> x , y, z
}
}
module.exports = Home;
What am i missing ? Is there something wrong with the way i have assigned or this is some bug ?
Any suggestion is highly appreciated.
Video
try to change
onPress={this.handleRoute('x')} // in this case handleRoute function is called as soon as render happen
to
onPress={() => this.handleRoute.bind('x')} //in this case handleRoute doesn't called as soon as render happen
You can change to this:
onPress={this.handleRoute.bind(this, 'x')}
or this:
onPress={() => this.handleRoute('x')}
The reason is that onPress takes a function as an argument. In your code, you are calling the function and returning the result immediately (when render is called) rather than referencing the function for React to call later on the press event.
The reason you need the bind(this) is because the function loses it's bound instance when you just do (this.handleRoute) and you have to tell it which this to use. The bind function takes the other arguments to call on the function later. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind for more descriptive info on bind.
There is another way in which you can bind in the constructor. You can read about ways to handle this in React here: https://facebook.github.io/react/docs/handling-events.html
onPress={this.handleevent.bind(this, 'A')}
or use this:
onPress={() => this.handleevent('B')}
Change
onPress={this.handleRoute('x')}
to
onPress={()=>this.handleRoute('x')}
Otherwise, the function gets invoked as soon as the render method gets called.
The reason for such behaviour is on every render, reference to the function is created.
So, to avoid that, use bind function OR arrow function to call on onPress