I am facing a very weird phenomenon regarding JavaScript variables, scopes and closures.
Here is a code for a React Native application:
import { View } from 'react-native';
import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler';
let someVar = false;
const JsTest = () => {
const gesture = Gesture.Pan()
.onUpdate(() => {
someVar = true;
console.log('someVar is set to true');
})
.onEnd(() => {
console.log(`someVar: ${someVar}`);
});
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<GestureDetector gesture={gesture}>
<View style={{flex: 1, backgroundColor: 'white'}}></View>
</GestureDetector>
</GestureHandlerRootView>
);
};
export default JsTest;
When I touch the screen, onUpdate callback is called so it sets the someVar
to true
.
When I release my finger, onEnd
is fired but the value of someVar
is false
.
Here are the logs:
LOG someVar is set to true
LOG someVar is set to true
LOG someVar is set to true
LOG someVar is set to true
LOG someVar is set to true
LOG someVar: false
However, if I create variables for callbacks instead of passing them inline, the value of someVar
is successfully updated.
Here is the altered code:
import { View } from 'react-native';
import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler';
let someVar = false;
const JsTest = () => {
const onUpdate = () => {
someVar = true;
console.log('someVar is set to true');
};
const onEnd = () => {
console.log(`someVar: ${someVar}`);
};
const gesture = Gesture.Pan().onUpdate(onUpdate).onEnd(onEnd);
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<GestureDetector gesture={gesture}>
<View style={{flex: 1, backgroundColor: 'white'}}></View>
</GestureDetector>
</GestureHandlerRootView>
);
};
export default JsTest;
Console output:
LOG someVar is set to true
LOG someVar is set to true
LOG someVar is set to true
LOG someVar is set to true
LOG someVar is set to true
LOG someVar is set to true
LOG someVar: true
LOG someVar: true
LOG someVar: true
How is this even possible? Note that someVar
is not a state variable, not a ref, it’s not even in the component function, it’s a top level variable in the file itself. So all the other functions in the file should have closure over it and be able to get its updated value. What’s so special about inline functions? Why do they behave differently?
I also tried with ref (using useRef
) and a variable inside the component function, the result is the same. The result is the same with regular functions (instead of arrow functions) as well.
Why does this happen?
7