useState hook not working inside onKeyPress handler in React Native's TextInput - react-native

I'm using useState to keep the value of an input, and I need make some stuff when the taps a specific key, so I'm try to use onKeyPress, but the method used to update the state is not working, any help aprecciated :)
Here how the code looks like:
...
function handleKeyPress(event) {
// This code looks like is not running, why?
setMessageInput('asdasdasdasd')
}
...
<TextInput onKeyPress={handleKeyPress} />
...

It looks like you need to bind the function to the onKeyPress event handler. You can easily accomplish this by using an arrow function.
function handleKeyPress(event) {
setMessageInput('asdasdasdasd')
}
...
<TextInput onKeyPress={(e) => handleKeyPress(e)} />

The problem with yours is a javscript statement , where functions in javascript needs explicit binding of this in class components and in functional components you can achieve the same by using fat arrow functions.
So try replacing the code with the below
const handleKeyPress = (event) => {
setMessageInput('asdasdasdasd')
}
...
<TextInput onKeyPress={(e) => handleKeyPress(e)} />
Hope it helps. feel free for doubts

I solved this problem, its a problem with async execution of another handler

Related

how to change element that fits a component to an element that fits a function in react native

I am a new react native developer, I found a component and I want to use it in a function, but it is not clear to me how I would change it, can I get a help?
Here is the component
import TagInput from 'react-native-tag-input';
...
<TagInput
value={this.state.emails}
onChange={(emails) => this.setState({ emails })}
labelExtractor={(email) => email}
text={this.state.text}
onChangeText={(text) => this.setState({ text })}
/>
I got the code from here https://bestofreactjs.com/repo/jwohlfert23-react-native-tag-input
I guess you are asking how to adapt the code to fit the functional component, which includes converting the this.setState.
React provides some thing called React hooks, which you can think of as a way to replace states and lifecycles. You can read more about it here here
In your case, it would go like this:
import { useState } from 'react';
...
// useState can only be called inside functional components
const [emails, setEmails] = useState([]);
const [text, setText] = useState('');
...
<TagInput
value={emails}
onChange={(emailTags) => setEmails(emailTags)} // to avoid naming confusion
labelExtractor={(email) => email}
text={text}
onChangeText={(inputText) => setText(inputText)}
/>
you don't need to convert the component itself, you can use it as it is, but you need to change its implementation.
Basically, if you want to use function components, which is highly recommended now, you need to change the usage of the state in the component which will contain the <TagInput>.
Instead of using "this" which points to the class itself, you need to implement a hook called useState.
You can find it the docs here: https://reactjs.org/docs/hooks-state.html

What is the difference between a set state and a set state with an arrow in react native

I am creating a function that handles some logic from a switch change, but the follow doesn't work, but when I add the arrow part it does, but I don't understand what the arrow is doing in this context????
Underlying logic that is getting triggered to call my function
const [verbose, setVerbose] = useState(false)
<Switch
trackColor={{ false: "#767577", true: "#81b0ff" }}
thumbColor={isEnabled ? "#f5dd4b" : "#f4f3f4"}
ios_backgroundColor="#3e3e3e"
onValueChange={userChangedVb}
value={verbose}
/>
What doesn't work:
function userChangedVb(vb) {
//other logic
setVerbose(!vb )
}
What does work:
function userChangedVb(vb) {
//other logic
setVerbose(vb => !vb )
}
Can someone explain why? I guess I don't know what the arrow is doing inside the set state call? I'm still new to react native and usually when I use or see the arrow its something like this () => to generate a new function.
EDIT: This is mostly from the example here, which has the expo emulator so its really easy to try/experiment this code: https://reactnative.dev/docs/switch#onchange
EDIT: part of the problem is the vb parameter comming in has already been changed, so if I use:
function userChangedVb(vb) {
//other logic
setVerbose(vb )
}
It works as intend.

How to create an rxjs Observable from TextInput (either onChange or onTextChange)

I want to create an observable from a change event that gets fired on a React Native TextInput component. TextInput comes with 2 change props that I'm aware of (onChangeText and onChange). From what I gather, you need to use onChange if you want access to the native event you need to use onChange.
I don't know much about the native event object. I am trying to create an rxjs observable using fromEvent.
First I created a ref in my functional component like this:
const sqftRef = useRef().current
Then I attached this ref to the TextInput component like this:
<TextInput
ref={sqftRef} // attach a ref
label='Sqft'
mode='flat'
textContentType='none'
autoCapitalize='none'
keyboardType='numeric'
autoCorrect={false}
value={String(formValues.sqft)}
dense
underlineColor={colors.colorOffWhite}
onChangeText={(text) => setText(text)}
onChange={e => {
// somehow create an observable from this event ???
}}
style={styles.inputStyles}
theme={inputTheme}
/>
I tried to create an Observable using fromEvent like this but it doesn't work. I get undefined is not an object (evaluating target.addEventListener):
fromEvent(sqftRef, 'onChange').subscribe(value => console.log(value))
I know my approach is all wrong. Hoping someone can point me in the correct direction.
I would emit events you need into a subject, then subscribe to the subject in other parts of your code.
Here's a simple React example that should get you started
function App() {
const textChange = new Subject<string>();
useEffect(() => {
// subscribe to
const subscription = textChange.asObservable().subscribe(console.log)
return () => subscription.unsubscribe()
}, [])
// Emit events with a subject
return <textarea onChange={(e) => {
textChange.next(e.target.value)
}}>
</textarea>
}
render(<App />, document.getElementById('root'));
Check out the example here: https://stackblitz.com/edit/react-ts-akoyfv
I think the problem is with assigning the current directly to the sqftRef. Try to define it without current, but use current when creating the Observable, like the following:
const sqftRef = useRef();
Then create the Observable within useEffect to make sure that the DOM is ready:
useEffect(() => {
fromEvent(sqftRef.current, 'onChange').subscribe((value) =>
console.log(value)
);
});
OK, I was able to figure it out with the help of Amer Yousuf and Alex Fallenstedt.
I did something similar to what Alex suggested, modifying his solution for React Native. One reason his solution wasn't working for me is that it is important to use the useRef hook to prevent the Observable from being re-created on each render. If the observable is recreated (on a re-render) and useEffect doesn't run again, then we won't have an active subscription to the newly (re-created) observable (useEffect never runs again). That's why my call to sqft$.next was originally only being called once (the first time until we re-render).
My solution looks like this:
let sqft$ = useRef(new BehaviorSubject(0)).current
useEffect(() => {
const sub = sqft$.subscribe({
next: (val) => {
// just testing stuff out here
updateForm('sqft', val)
updateForm('lot', val * 2)
}
})
// this is only relevant to my use case
if (activeReport) sqft$.next(activeReport.sqft)
return () => sub.unsubscribe()
}, [activeReport])
and of course I call this in onChangeText:
onChangeText={(text) => {
sqft$.next(text)
}}
So this is working right now. I still feel like there may be a better way using onChange(e => ...stuff). I will leave this question open for a little bit in case anyone can break down how to do this using nativeEvent or explain to me how I can access an event off the TextInput component.

How to pass function to other components in React Native?

I have the following snack:
https://snack.expo.io/#sj458147/rewrite39
The App.js imports StepOne, StepTwo, StepThree, StepFour, and MyScrollView. Within this I want to make the function moveToPage from MyScrollView accessible to the components StepOne, StepTwo, StepThree and StepFour how can I achieve this? I have tried to use props (following various React tutorials) without success. Is using props the best way to achieve this, are there any pitfalls to this approach? Thanks
The issue that you are having is that you are not getting a reference to the your instance of MyScrollView so you cannot access the functions that are in it
If you add the following to your MyScrollView component, this will allow you to pass the reference back as the prop onRef
componentDidMount () {
// this creates the reference when the component mounts
if (this.props.onRef) {
this.props.onRef(this);
}
}
componentWillUnmount () {
// this removes the reference when the component unmounts
if (this.props.onRef) {
this.props.onRef(undefined);
}
}
You can then use the onRef prop as follows
<MyScrollView
onRef={ref => {this.scrollView = ref}}>
<StepOne next={()=> this.scrollView.moveToPage(2)}/> // you may wish to add a protection to make sure that this.scrollView is not null.
<StepTwo />
<StepThree />
<StepFour />
</MyScrollView>
You can see it working in this updated snack
https://snack.expo.io/#andypandy/creating-onref-prop-for-custom-scrollview
you can pass anything in props,if the second component is child of first.
_myFunction(val){} //do something
render(){
return(
<Second ABC={(val)=> this._myFunction(val) } /> //here the props name is ABC
)
}
and you can use it in child like this:
this.props.ABC("ANYTHING_YOU_WANT_TO_PASS")

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