if-else statement inside jsx not working as expected - react-native

I am trying to animate an image in and out when clicked using React Native reanimated, but the JSX if else condition is not working quite right. Below is the code that works, but only works when clicked for the first time. The state toggled is set to true, so when clicked again it should set the size back to the original and the image should animate back to it and vice versa.
The setup is like so:
export default () => {
const newNumber = useSharedValue(100);
const [Toggled, setToggled] = useState(false);
const style = useAnimatedStyle(() => {
return {
width: withSpring(newNumber.value),
height: withSpring(newNumber.value, { damping: 10,
stiffness: 90, }),
};
});
onPress={() => {
{Toggled ? newNumber.value = 100 : newNumber.value = 350; setToggled(true)}
}}
The problem is when I try to add the newNumber.Value = 100 when setting Toggled to false, it gives me an error. I try to add it like this :
{Toggled ? newNumber.value = 100; setToggled(false) : newNumber.value = 350; setToggled(true)}
Why does it accept the first one but not the second?
If I use this, it works, but can it be done the other way?
const isToggled = Toggled;
if (isToggled) {
// alert('Is NOT Toggled');
newNumber.value = 100;
setToggled(false)
} else {
// alert('Is Toggled');
newNumber.value = 350;
setToggled(true)
}
Thanks

It looks you are just setting a value to newNumber base on Toggled, and then setting the Toggled to its opposite value. So why not do
onPress={() => {
newNumber.value = Toggled ? 100 : 350
setToggled(prev=>!prev)
}}

Related

Why variable value inside of canvas function not incrementing?

Here is an open GitHub issue Github Issue
Here is a Expo Snack
For some reason, variables are not incrementing inside the canvas function while outside works just fine. Please have a look at my code:
function home ({ navigation }) {
const [counter, setCounter] = useState(330);
useEffect(() => {
const timeout = setTimeout(() => {
setCounter(counter + 1);
}, 1000);
return () => {
clearTimeout(timeout);
};
}, [counter]);
console.log('outside ', counter);
const _onGLContextCreate = (gl) => {
var ctx = new Expo2DContext(gl);
// setInterval(() => {
// console.log('set interval doesnt refresh too ', counter);
// }, 1000);
console.log('inside ', counter);
let circle = {
x: counter,
y: 100,
radius: 30,
color: 'black'
}
let circle2 = {
x: 400,
y: 100,
radius: 30,
color: 'blue'
}
function drawCircle() {
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2);
ctx.fillStyle = circle.color;
ctx.fill();
ctx.closePath();
}
function drawCircle2() {
ctx.beginPath();
ctx.arc(circle2.x, circle2.y, circle2.radius, 0, Math.PI * 2);
ctx.fillStyle = circle2.color;
ctx.fill();
}
function update() {
drawCircle();
drawCircle2();
}
function animate() {
ctx.clearRect(0, 0, ctx.width, ctx.height);
requestAnimationFrame(animate);
update();
ctx.flush();
}
animate();
ctx.stroke();
ctx.flush();
};
return (
<GLView style={{ flex: 1 }} onContextCreate={_onGLContextCreate} />
);
}
export { home };
Here is what logs show:
outside 330
inside 330
outside 331
outside 332
outside 333
outside 334
outside 335
outside 336
outside 337
Does anybody know why is being read once in canvas and what could be the solution to increment it as in ouside in canvas function?
I don't know exactly what is the cause, but I found issues in the architecture, and when I fixed them it worked.
TL;DR see result here https://snack.expo.dev/#dozsolti/expogl-ball
You don't need to rerender the component because you update only the canvas so the useState will be swapped with useRef. Also, you probably meant to update the counter every second so for that I changed useTimeout with useInterval. (The useTimeout worked only because it was in a useEffect with the counter dependency which was updated, sort of like calling himself. The correct way was to use a useEffect when the component was loaded and a setInterval)
After that you needed to swap counter with counter.current
Keep in mind that the _onGLContextCreate is running only once so the circle and circle2 objects aren't changing. That's we I changed changed the x value in the update
Besides those, everything looks fine, I guess you optimize the code a little bit, like create a single DrawCircle function that takes x,y as parameters, and so on.

undefined is not an object (evaluating 'fun.__callAsync') trying to use setTimeout in a component

I'm using React Native and Reanimated and I want an animation to play after 2 seconds.
When a user moves a card, the card should stay at it's new position for 2 seconds, and then move back to it's place.
This is what I have:
const panGesture = useAnimatedGestureHandler<PanGestureHandlerGestureEvent>({
onActive: event => {
translateX.value = event.translationX;
if (event.translationX <= 0) {
// disabling swiping from right to left
translateX.value = 0;
}
},
onEnd: event => {
const shouldStick = translateX.value >= TRANSLATE_X_THRESHOULD;
if (shouldStick) {
translateX.value = withTiming(120);
runOnJS(moveBack)(translateX);
} else {
translateX.value = withTiming(0);
}
},
});
I tried using setTimeOut to count 2 seconds, and then update translateX but I get this error:
undefined is not an object (evaluating 'fun.__callAsync')
This is moveBack function:
const moveBack = (translateX: Animated.SharedValue<number>) => {
console.log("TRANSLATEX: " + translateX);
setTimeout(() => {
translateX.value = 0;
}, 2000);
}
I don't even see the TRANSLATEX log, so I guess it won't even get there.
I can't really figure out what's the problem or how to word it so I can find a solution.
The solution was way easier than I thought.
I'm using Reanimated 2.2.0 and there is withDelay option to add to the animation and it works great.
This is what I added after translateX.value = withTiming(120); (instead of the runOnJs line):
translateX.value = withDelay(2000, withTiming(0));
So right after setting translateX to 120, it waits 2 seconds, and then setting the value back to 0.
when using runOnJS
const doSomething = () => {
...
} // declare arrow function before runOnJS
runOnJS(doSomething)(arg)
function doSomething(){
...
} // can declare normal function before/after runOnJS coz of hoisting

Reset the initial state value in Recat Native

Requirement: I have to blink a View for 2 sec with 2 different color (for ex red and white).
I can do this by using this code -
const [state, setState] = React.useState(false)
const [initialState, setInitialState] = React.useState(0)
React.useEffect(() => {
if (initialState < 2){
let interval = setInterval(() => {
setState(true)
setInitialState(initialState + 1)
setTimeout(() => {
setState(false)
}, 80);
}, 300);
setTimeout(() => {
clearInterval(interval)
}, 600);
}
}, [initialState])
and called it like -
<View style={{...styles.mainContainer, backgroundColor: state ? Colors.GRO7 : Colors.GRC9}}>
Another Requirement: I have another screen from it i an change the address, on successful address change i have to blink this view again for 2 sec. I'm not sure where i can reset the initial value to 0 again.
I am new In react native, could some one guide me how to achieve this functionality
Can‘t completely understand what‘s your target.
Here is a blinking text sample
you can pass in the initial value to this component instead of defining 0 in this line:
const [initialState, setInitialState] = React.useState(0)
you could have a param to pass in and put it instead of 0 so that every time that param changes this component will re render. and so you get a new initial state.
for example:
const [initialState, setInitialState] = React.useState(initialValue)

Save Sketched lines in LocalStorage

Sorry im posting this here
I want to save the info of each line i drew on canvas(the save action would be called onChange)
so i can retrieve this data and draw it on canvas again in case the user change screen or something.
I'm using expo-pixi to draw a image and sketch over it
onChangeAsync = async (param) => {
// here i want on change code i get the line informantion and store it
}
onLayout = async ({
nativeEvent: {
layout: { width, height },
},
}) => {
this.setState({
layoutWidth: width,
layoutHeight: height,
})
this.onReady();
}
onReady = async () => {
const { layoutWidth, layoutHeight, points } = this.state;
this.sketch.graphics = new PIXI.Graphics();
if (this.sketch.stage) {
if (layoutWidth && layoutHeight) {
const background = await PIXI.Sprite.fromExpoAsync(this.props.image);
background.width = layoutWidth * scaleR;
background.height = layoutHeight * scaleR;
this.sketch.stage.addChild(background);
this.sketch.renderer._update();
}
}
};
// The sketch component is pretty much as the example which comes with the lib
<Sketch
ref={ref => (this.sketch = ref)}
style={styles.sketch}
strokeColor={this.state.strokeColor}
strokeWidth={this.state.strokeWidth}
strokeAlpha={1}
onChange={this.onChangeAsync}
onReady={this.onReady}
/>
Does anyone have any clue? im kind of desperate
Thanks

Mobx observable properties

After adding observable properties to an array with this action
#action
improvePrograms = function() {
let data = this.dataPro;
this.dataProImproved = data;
for (i = 0; i < data.length; i++) {
extendObservable(this.dataProImproved[i], {
wishedFor: false,
inCart: false,
sold: false
});
}
};
I tried to change the values of the properties with:
#action
addToWishList = function(item) {
for (i = 0; i < this.dataProImproved.length; i++) {
if (this.dataProImproved[i].program_id === item.program_id && this.dataProImproved[i].wishedFor === false) {
this.dataProImproved[i] = { ...this.dataProImproved[i], wishedFor: true };
console.log("Program added to wish list: ", this.dataProImproved[i]);
this.getWishList();
}
}
};
everything seemed fine but the component where I use the observable property for changing colors doesn't react or rerender even when the value of the properties are changed to true.
<TouchableOpacity onPress={!this.props.program.wishedFor ? this.onSelectWish : this.onDeselectWish}>
<FontAwesome
style={{ padding: 7 }}
name={this.props.program.wishedFor === false ? "heart-o" : "heart"}
size={28}
color={!this.props.program.wishedFor ? "#c5d1e8" : "#ff1d25"}
/>
</TouchableOpacity>
Can someone please explain to me what I am doing wrong here. The class component is decorated with #observer and injected with the store.
So I made it work passing the data array through:
#computed get getDataProImproved(){return this.dataProImproved}
And don't forget to slice the array before passing it to the FlatList...
Everything reacts fine...