What is the difference between a set state and a set state with an arrow in react native - 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.

Related

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.

React Native useState change from a function is not re-rendering the components

I've tried a lot of answers given to similar questions but nothing is fixing my problem as I'm changing the state in a function which I'm calling on the press of a button in a third-part library I'm using.
I'm using react-native-horizontal-date-picker and upon select a date I'm calling a function in which I'm changing the state.
<HorizontalDatePicker
pickerType={'date'}
dayFormat={'Do'}
monthFormat={'MMM'}
yearFormat={'YYYY'}
returnDateFormat={'DD-MM-YYYY'}
onDateSelected={(date) => {
if (date) {
getTimeData()
}
}}
/>
Then in my getTimeData function I'm updating the const [timeSlots, setTimeSlots] = useState([]); state:
function getTimeData() {
...
if (timeAvailable) {
setTimeSlots(finalTimeSlots)
} else if (!timeAvailable) {
setTimeSlots([])
}
...
}
based on the timeSlots array I'm updating the UI, now I have to tap twice on the date to be able to see the results getting rendered.
I'm passing timeSlots to another custom component that I made:
<TimePicker timeSlotsArray={timeSlots} />
How do I achieve this in this scenario?

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

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

Undefined is not an object in React Native

Hi ninjas quick question I have a button which runs the following
onPress={this.props.productStore.closeModal}
but if I change the code to have a function:
closeModal() {
this.props.productStore.closeModal;
//alert('close modal');
}
and the button trigger onPress={this.closeModal} I get undefined is not an object. (this.props.productStore.closeModal is a mobx store which updates isModalVisible to false). If I uncomment alert in closeModal function the alert runs fine. Any help with resolving is appreciated. Thanks in advance
In the second variant, this.props is undefined because the function closeModal is not bound to this. Use either the arrow function syntax like below:
closeModal = () => {
this.props.productStore.closeModal();
}
or bind the function to this.
onPress={this.closeModal.bind(this)}
Another problem that I noticed in the code is you are not calling the function. You should call the function.
this.props.productStore.closeModal();

How to handle a button press inside react-navigation titlebar

I am pretty new to react-native and I am currently handling navigation for my app using react-navigation.
I want to be able to add a button to my app's title bar created by react-navigation and be able to press a button to call a function.
static navigationOptions = ({ navigation }) => {
const { params } = navigation;
return {
title: 'Assign To',
headerRight: (
<Button
title='Back'
onPress={() => params.handlePress()}
/>
),
};
};
This is close to what I read from the react-navigation docs, but it I keep getting an error of undefined is not an object.
componentDidMount() {
this.props.navigation.setParams({ handlePress: () => this.myFunction.bind(this) });
}
I have myFunction defined inside my component as follows
myFuntion() {
//...
}
Any help is highly appreciated
I'm going to answer this, with a little more explanation. The problem as you know was that you were combining the syntax of two similar approaches. You can use either the .bind syntax: handlePress: this.myFunction.bind(this) or the so-called fat-arrow syntax: handlePress: () => this.myFunction. They are more-or-less equivalent and there are opinions that the fat-arrow syntax supersedes the bind syntax (and, as always, opinions to the contrary :) ). There are differences, such as (quoting from this):
Arrow functions are always anonymous, which means you can't, for
instance, reliably call them recursively (since you don't have a
reliable lexical name to use).
Arrow functions actually create
lexical bindings for this, super, and arguments. Only this is bound
by .bind(..).
Arrow functions cannot be used in new expressions,
while bind(..) bound functions can.
Also, given that this is a react native question, it might help to be aware of this interesting article:
https://medium.freecodecamp.org/why-arrow-functions-and-bind-in-reacts-render-are-problematic-f1c08b060e36
For most elements you can use the onPress() function in react-native
onPress={() => { Alert.alert("You clicked me") } }
If you need to bind you can usually do it with the following example:
onPress={this.functionName.bind(this)}