Adding variables in React Native - react-native

I'm experiencing inconsistencies when doing calculations using TextInputs (CustomInput) in React Native. For example; if I input '5' under Scope Height and calculate, I get a different number than if I replace the 'scopeHeight' variable with 5. The other input variables seem to work correctly.
const SignInScreen = () => {
const [scopeHeight, setScopeHeight] = useState('');
const [pelletWeight, setPelletWeight] = useState('');
const [pelletSpeed, setPelletSpeed] = useState('');
const [firstZero, setFirstZero] = useState('');
const [secondZero, setSecondZero] = useState('');
const [targetDistance, setTargetDistance] = useState('');
const [joules, setJoules] = useState('');
const [ftlb, setFtlb] = useState('');
const [hold, setHold] = useState('');
const {height} = useWindowDimensions();
const onCalcPressed = () => {
var footPound = ((pelletSpeed**2)*pelletWeight)/450240
setFtlb(footPound.toFixed(1)+ " ft.lb");
var joule = footPound*1.356
setJoules(joule.toFixed(1) + " J");
var pelletDrop = -490.33*((targetDistance/pelletSpeed)**2)
var scopeDrop1 = ((-490.33*firstZero**2)/pelletSpeed**2)-scopeHeight
var scopeDrop2 = targetDistance/firstZero
var scopeDrop = (scopeDrop1*scopeDrop2)+scopeHeight
var difference = pelletDrop-scopeDrop
var hold = difference*32.8084/targetDistance
setHold(hold.toFixed(2) + " MRAD");
}
return (
<View style={styles.root}>
<Image
source={Logo}
style={[styles.logo, {height: height * 0.3}]}
resizeMode="contain"
/>
<Text style={[styles.baseText]}>Scope Height (cm)</Text>
<CustomInput
placeholder="Scope Height (cm)"
value={scopeHeight}
setValue={setScopeHeight}
/>
<Text style={[styles.baseText]}>Pellet Weight (grains)</Text>
<CustomInput
placeholder="Pellet weight (grains)"
value={pelletWeight}
setValue={setPelletWeight}
/>
<Text style={[styles.baseText]}>Pellet Speed (ft/s)</Text>
<CustomInput
placeholder="Pellet speed (feet/second)"
value={pelletSpeed}
setValue={setPelletSpeed}
/>
<Text style={[styles.baseText]}>First Zero (ft)</Text>
<CustomInput
placeholder="First zero (feet)"
value={firstZero}
setValue={setFirstZero}
/>
<Text style={[styles.baseText]}>Second Zero (ft)</Text>
<CustomInput
placeholder="Second zero (feet)"
value={secondZero}
setValue={setSecondZero}
/>
<Text style={[styles.baseText]}>Target Distance (ft)</Text>
<CustomInput
placeholder="Target Distance (feet)"
value={targetDistance}
setValue={setTargetDistance}
/>
<CustomButton text="Calculate" onPress={onCalcPressed} />
<Text style={{fontWeight: 'bold'}}>Energy</Text>
<Text>{ftlb}</Text>
<Text>{joules}</Text>
<Text>{hold}</Text>
</View>
)
}
I've realized that the problem is that adding and subtracting the variables isn't working as I'd expected (scopeHeight + scopeHeight) returns '55' with a value of 5, rather than 10. Is there any way around this? Any help would be much appreciated!

Related

why it is not working to remove if it the same color name?

I have a problem
My currentColor goes not to null, If I Press a color I set the color to currentColor, if the same color is again pressed then I remove the color (I set currentColor to null). but its not working
const ModalProductSizeColor = forwardRef<BottomSheetModal, IModalProductSizeColor>(({ onPress }, ref) => {
const navigation = useNavigation<NativeStackNavigationProp<RootStackParams>>();
const [currentColor, setCurrentColor] = useState<ColorsOptions | null>(null);
const [sizeScreen, setSizeScreen] = useState<boolean>(false);
const snapPoints = useMemo(() => ['25%', 250], []);
const handleSetCurrentColor = (color: ColorsOptions) => {
console.log(currentColor + 'current in func');
currentColor === color ? setCurrentColor(null) : setCurrentColor(color)
};
console.log(currentColor);
return (
<BottomSheetModal
ref={ref}
index={1}
snapPoints={snapPoints}
handleIndicatorStyle={[s.handleStyle, s.handleColorWhite]}
backdropComponent={BottomSheetBackdrop}
>
<Text style={s.title}>test</Text>
<Colors
colors={ColorsData}
onPress={handleSetCurrentColor}
onLongPress={(x) => console.log(x)}
containerStyle={s.containerStyle}
/>
<View style={s.btnContainer}>
<Pressable style={ButtonStyles.full}>
<Text style={s.btnText}>Fertig</Text>
</Pressable>
</View>
</BottomSheetModal>
)
});
In my function when I console.log currentColor its null but outside of the function it is setted , I dont check anything anymore I am very thankful for your help
Assuming your Colors component passes the color to your handleSetCurrentColor, you could try to set your currentColor like this
...
console.log(currentColor + 'current in func');
setCurrentColor(prevCurrentColor => prevCurrentColor === color ? null : color)
...

Fail to prevent re-render by React.memo

I am building a react native app for which has a form page contains a lot of textInput and buttons. Each of fields do not causing performance issue.
However, when they are put together, the application will show js thread frame drops in the Perf Monitor. So I think the page is re-rendering all the components when any of the state is changed.
I tried 2 methods.
Moving components out of the main export function.
Using React.memo.
Unfortunately, both of them are not working. The app still lag and re-render every time for all components.
So I created a simple case for it. You may see the code below.
I would like to only re-render the ChildItem for only the respective state changed. For now, console will log from 1 to 5 for any button clicked. Since the props passed to memo component is not changed, I expect the console will only log 1 respective sentence for specific index when button is pressed.
import React, {useState, memo} from 'react';
import { View, Text, Button } from 'react-native';
const ChildeItem = memo( ({index, value, onPress}) =>{
console.log(`ChildeItem ${index} rendered`);
return(
<View style={{flexDirection: 'row'}}>
<Text style={{flex: 1, textAlign: 'center'}}>
{value}
</Text>
<View style={{flex: 1}}>
<Button
onPress={onPress}
title={"+"}
/>
</View>
</View>
)
});
export default function TestScreen({navigation}) {
const [value1, setValue1] = useState(0);
const [value2, setValue2] = useState(0);
const [value3, setValue3] = useState(0);
const [value4, setValue4] = useState(0);
const [value5, setValue5] = useState(0);
return(
<View>
<ChildeItem index={1} value={value1} onPress={()=>{setValue1(value1+1);}} />
<ChildeItem index={2} value={value2} onPress={()=>{setValue2(value2+1);}} />
<ChildeItem index={3} value={value3} onPress={()=>{setValue3(value3+1);}} />
<ChildeItem index={4} value={value4} onPress={()=>{setValue4(value4+1);}} />
<ChildeItem index={5} value={value5} onPress={()=>{setValue5(value5+1);}} />
</View>
)
}
Or I have any misunderstanding for React.memo? Any help will be appreciated. Thanks.
Your index and value props are ok for memoization, but your onPress prop causes re-render because on every render of the TestScreen, your onPress prop functions are re-created, so it's reference changes. You can prevent this by using useCallback hook.
export default function TestScreen({navigation}) {
const [value1, setValue1] = useState(0);
const [value2, setValue2] = useState(0);
const [value3, setValue3] = useState(0);
const [value4, setValue4] = useState(0);
const [value5, setValue5] = useState(0);
// Use useCallback for each function
const onPress1 = useCallback(() => setValue1(value1+1), [value1]);
const onPress2 = useCallback(() => setValue2(value2+1), [value2]);
const onPress3 = useCallback(() => setValue3(value3+1), [value3]);
const onPress4 = useCallback(() => setValue4(value4+1), [value4]);
const onPress5 = useCallback(() => setValue5(value5+1), [value5]);
return(
<View>
<ChildeItem index={1} value={value1} onPress={onPress1} />
<ChildeItem index={2} value={value2} onPress={onPress2} />
<ChildeItem index={3} value={value3} onPress={onPress3} />
<ChildeItem index={4} value={value4} onPress={onPress4} />
<ChildeItem index={5} value={value5} onPress={onPress5} />
</View>
)
}
By using useCallback hook, you're memoizing the onPress functions, so they are re-created only when the relevant value changes.

How I make this input in react native customable?

I need a verification input and want to make it like in this picture:
I know how to make it but not customable. Maybe I want to make 4 or 5.
I can make it like this
const input2 = useRef();
const input3 = useRef();
const input4 = useRef();
const input5 = useRef();
<TextInput onChangeText={(e) => (setText(e), input2.focus() ) } />
<TextInput ref={(input) => { input2 = input } } />
But then its hardcoded. How can I make it customable ?
You could use react-native-confirmation-code-field which is highly customizable.
Here is a basic example using 4 inputs instead of 5. In fact, you can use any number of inputs.
const [value, setValue] = useState("")
const ref = useBlurOnFulfill({ value, cellCount: 4 })
const [props, getCellOnLayoutHandler] = useClearByFocusCell({
value,
setValue,
})
return (
<SafeAreaView style={{ margin: 40, marginTop: 80 }}>
<CodeField
ref={ref}
{...props}
// Use `caretHidden={false}` when users can't paste a text value, because context menu doesn't appear
value={value}
onChangeText={setValue}
cellCount={4}
keyboardType="number-pad"
textContentType="oneTimeCode"
renderCell={({ index, symbol, isFocused }) => (
<Text
style={{
width: 40,
height: 40,
lineHeight: 38,
fontSize: 24,
borderWidth: 2,
borderColor: "#00000030",
textAlign: "center",
}}
key={index}
onLayout={getCellOnLayoutHandler(index)}>
{symbol || (isFocused ? <Cursor /> : null)}
</Text>
)}
/>
</SafeAreaView>
In general this component is very customizable. You can render your own input components, etc.
The above code yields the following very simple output. Designing the exact same component as given in your picture boils to designing a custom cell inside the render function.

How to get ref x, y position in functional component in react-native?

I want to get the x, y position when the text cursor is focused on TextInput.
how to get ref position?
here is my code
const Code = () => {
const emailInput = useRef();
const scrollViewRef = useRef();
const [email, setEmail] = useState<string>('');
const scrollToEmail = () => {
// I want to scroll the y position of the scroll to the center where the TextInput's cursor is focused.
};
return (
<SafeAreaView style={{ flex: 1}}>
<ScrollView keyboardShouldPersistTaps="handled" ref ={scrollViewRef}>
<KeyboardAvoidingView enabled behavior={'padding'}>
<TextInput
ref={emailInput}
value={email}
returnKeyType="done"
onChangeText={(text) => setEmail(text)}
onFocus = {() => scrollToEmail()} <== function works here!
/>
</KeyboardAvoidingView>
</ScrollView>
</SafeAreaView>
);
};
export default Code;
i tried this
1.
const handler = findNodeHandle(emailInput.current);
console.log(
emailInput.measure(handler, (x, y, width, height) => {
console.log(y);
}),
); <== TypeError: emailInput.measure is not a function
const handler = findNodeHandle(emailInput.current);
console.log(emailInput.current.getBoundingClientRect()); <== TypeError: emailInput.current.getBoundingClientRect is not a function
there is no way get the ref's postition in a functional component?
You can use onLayout prop on the ScrollView to the the height, width, X and Y value.
If you want to use the ref, you have to set or console.log the X and Y value on a useLayoutEffect. This is because you need to wait for the component to be rendered and "drawn" before you get the information, otherwise you will get only 0

How to rerender FlatList inside of SmoothPicker to change data with react hooks

I'm trying to create an SmoothPicker like that:
I'm using react-native-smooth-picker and all works fine, except when I'm Changing to Feet.
When I change to Feet, I want that the list will rerender and change the data to Feet parameters, but it only happened after a scroll. Is there a way to do that?
here is my code:
const HeightPicker = () => {
const [isFeet, setIsFeet] = useState(false)
const listRef = useRef(null)
let metersHeights = []
const feetHeights = new Set()
for (i = 140; i <= 220; i++) {
metersHeights.push(i)
feetHeights.add(centimeterToFeet(i))
}
const [selected, setSelected] = useState(40)
return <View
style={{
backgroundColor: 'rgb(92,76, 73)',
paddingBottom: 20
}} >
<Toggle
style={{
alignSelf: 'flex-end',
marginVertical: 20,
marginEnd: 20
}}
textFirst="Feet"
textSecond="Meters"
onChange={(change) => {
setIsFeet(change)
}} />
<SmoothPicker
ref={listRef}
onScrollToIndexFailed={() => { }}
initialScrollToIndex={selected}
keyExtractor={(value) => value.toString()}
horizontal
showsHorizontalScrollIndicator={false}
magnet={true}
bounces={true}
extraData={isFeet}
data={isFeet ? [...feetHeights] : metersHeights}
onSelected={({ item, index }) => setSelected(index)}
renderItem={({ item, index }) => (
<Bubble selected={index === selected}>
{item}
</Bubble>
)}
/>
</View>
}
You should separate the feet & meters (the function tha generates them).
Set data with useState & make meters as default
make use of useEffect to change the data everytime you toggle.
...
useEffect(() => {
handleData(isFeet)
},[isFeet]);
const handletData = (isFeet) => {
if(isFeet){
setData(feet)
}else{
setData(meters)
}
}
....
data={data}
...