React Native keyboard disappears after each letter press - javascript

I am working on a register page on react native where I want to make an onboarding register page so I have my TextInputs in a separate function to switch between the text input when you go to the next onboard screen. But when I press on an input and want to start typing I can get one press of on the keyboard before it goes down again.
I have tried moving my useEffect inside that function then the issue is solved but the other functions cannot get the values then.
//Content
export default function Register({ navigation }) {
const [name, onNameChange] = useState("");
//get current slide index point
const [currentSlideIndex, setCurrentSlideIndex] = useState(0);
const ref = React.useRef(null);
//update slides upon index
const updateCurrentSlideIndex = (e) => {
const contentOffsetX = e.nativeEvent.contentOffset.x;
const currentIndex = Math.round(contentOffsetX / width);
setCurrentSlideIndex(currentIndex);
};
//button function to go to next slide
const goNextSlide = () => {
const nextSlideIndex = currentSlideIndex + 1;
if (nextSlideIndex != slides.length) {
const offset = nextSlideIndex * width;
ref?.current?.scrollToOffset({ offset });
setCurrentSlideIndex(nextSlideIndex);
}
};
const RegInputs = () => {
if (currentSlideIndex == 0) {
return (
<KeyboardAvoidingView style={{ flex: 1 }} behavior="position">
<BlurView intensity={20} tint="light">
<Text style={styles.label}>Name</Text>
<TextInput
value={name}
onEndEditing={(text) => onNameChange(text)}
style={styles.input}
errorStyle={{ color: "red" }}
errorMessage="Incorrect Username"
/>
</BlurView>
</KeyboardAvoidingView>
);
} else if (currentSlideIndex == 1) {
return <View></View>;
} else if (currentSlideIndex == 2) {
return <View></View>;
}
};
const handleRegisterPress = () => {
Alert.alert("NAME: " + name);
};
const Slide = ({ item }) => {
return (
<View style={{ alignItems: "center" }}>
<View style={{ width }}>
<Image
source={item.image}
style={{
width: imagewidth,
height: imageHeight,
resizeMode: "contain",
alignSelf: "center",
}}
/>
</View>
<Text style={styles.heading}>{item.title}</Text>
<RegInputs />
</View>
);
};
const Footer = () => {
return (
<View style={{ height: height * 0.15, width, paddingHorizontal: 20 }}>
<View
style={{
flexDirection: "row",
justifyContent: "center",
marginTop: 20,
}}
>
{slides.map((_, index) => (
<View
key={index}
style={[
styles.indicator,
currentSlideIndex == index && {
backgroundColor: "white",
borderColor: "#68BF7B",
borderWidth: 2,
width: 16,
opacity: 1,
},
]}
/>
))}
</View>
<View style={{ marginBottom: 20 }}>
{currentSlideIndex == slides.length - 1 ? (
<View>
<TouchableOpacity onPress={handleRegisterPress}>
<View style={styles.nextbtn}>
<Text style={styles.nextbtnText}>Finish</Text>
</View>
</TouchableOpacity>
</View>
) : (
<TouchableOpacity onPress={goNextSlide}>
<View style={styles.nextbtn}>
<Text style={styles.nextbtnText}>Next</Text>
</View>
</TouchableOpacity>
)}
<View style={{ flexDirection: "row" }}>
<Text style={styles.bodyreg}>Already have an account?</Text>
<TouchableOpacity onPress={() => navigation.navigate("Login")}>
<Text style={styles.bodylinkreg}>Login</Text>
</TouchableOpacity>
</View>
</View>
</View>
);
};
}

change the prop onEndEditing in TextInput to onChangeText, and reload the entire app

Related

java.lang.Double cannot be cast to abie47_0_0.com.facebook.react.bridge.ReadableMap

I am encountering the "java.lang.Double cannot be cast to abie47_0_0.com.facebook.react.bridge.ReadableMap" error when opening the app with my android while using react-native-gifted-charts.
This error showing after using react-native-gifted charts
this is the code of the screen, can anyone help or advise what could be the problem and ways to resolve it
Error I got
Below is the code
import styles from "./styles";
import CoinDetailedHeader from "./components/CoinDetailedHeader/index";
import { AntDesign } from "#expo/vector-icons";
import { ChartDot, ChartPath, ChartPathProvider, ChartYLabel } from "#rainbow-me/animated-charts";
const CoinDetailedScreen = () => {
const {
image: { small },
name,
symbol,
prices,
market_data: { market_cap_rank, current_price, price_change_percentage_24h, },
} = Coin;
const [coinValue, setCoinValue] = useState("1");
const [usdValue, setUsdCoinValue] = useState(current_price.usd.toString());
const percentageColor = price_change_percentage_24h < 0 ? '#ea3943' : '#16c784';
const chartColor = current_price.usd > prices[0][1] ? '#16c784' : '#ea3943';
const screenWidth = Dimensions.get('window').width;
const changeCoinValue = (value) => {
setCoinValue(value);
const floatValue = parseFloat(coinValue) || 0;
setUsdCoinValue((floatValue * current_price.usd).toString());
};
const changeUsdValue = (value) => {
setUsdCoinValue(value);
const floatValue = parseFloat(value.replace(',', '.')) || 0;
setCoinValue((floatValue / current_price.usd).toString());
}
const formatCurrency = (value) => {
"worklet";
if (value === "") {
return `$${current_price.usd.toFixed(2)}`
}
return `$${parseFloat(value).toFixed(2)}`
}
return (
<View style={{ paddingHorizontal: 10 }}>
<ChartPathProvider data={{
points: prices.map(([x, y]) => ({ x, y })),
smoothingStrategy: 'bezier',
}}>
<CoinDetailedHeader
image={small}
symbol={symbol}
marketCapRank={market_cap_rank}
/>
<View style={styles.priceContainer}>
<View>
<Text style={styles.name}>{name}</Text>
<ChartYLabel
format={formatCurrency}
style={styles.currentPrice}
/>
</View>
<View style={{ backgroundColor: percentageColor, paddingVertical: 8, paddingHorizontal: 3, borderRadius: 5, flexDirection: 'row' }}>
<AntDesign name={price_change_percentage_24h < 0 ? 'caretdown' : 'caretup'}
size={12} color={'white'} style={{ alignSelf: 'center', marginRight: 5 }} />
<Text style={styles.priceChange}>{price_change_percentage_24h.toFixed(2)}%</Text>
</View>
</View>
<ChartPath height={screenWidth / 2} strokeWidth={2} stroke={chartColor} width={screenWidth} />
<ChartDot style={{ backgroundColor: chartColor }} />
<View style={{ flexDirection: 'row' }}>
<View style={{ flexDirection: 'row', flex: 1 }}>
<Text style={{ color: 'white', alignSelf: 'center' }}>{symbol.toUpperCase()}</Text>
<TextInput style={styles.input} value={coinValue} keyboardType='numeric' onChangeText={changeCoinValue} />
</View>
<View style={{ flexDirection: 'row', flex: 1 }}>
<Text style={{ color: 'white', alignSelf: 'center' }}>USD</Text>
<TextInput style={styles.input} value={usdValue} keyboardType='numeric' onChangeText={changeUsdValue} />
</View>
</View>
</ChartPathProvider>
</View>
);
};
export default CoinDetailedScreen;
Try updating following packages to mentioned versions
"react-native-linear-gradient": "2.6.2",
"react-native-svg": "12.1.0",
Ref : java.lang.Double cannot be cast to com.facebook.react.bridge.ReadableMap

Issue with updating an array in React Native

I am trying to work through a problem with my array state in React Native and correctly updating the array of objects when I click a button on one of the components.
Here is a video of the problem occurring, which is probably a better way to explain the issue: https://cdn.discordapp.com/attachments/935693286566416417/953045147397001276/RPReplay_Final1647294055.MP4
Here's the relevant code that might offer some insight:
MealPlanner.Js
const MealPlannerScreen = props => {
const minDate = new Date();
const [mealPlannerData, setMealPlannerData] = useState([]);
const [loading, setLoading] = useState(true)
const [selectedDate, setSelectedDate] = useState("03/13/2022")
const [breakfast, setBreakfast] = useState([])
const getMealPlannerData = async(date = '03/13/2022') => {
const isDataAvailable = await AsyncStorage.getItem("meal_planner")
if (isDataAvailable) {
const parsedData = JSON.parse(isDataAvailable)
let breakfastData = parsedData.filter(function (e) {
return ((e.date = date) && (e.meal == 'Breakfast'));
});
let lunchData = parsedData.filter(function (e) {
return ((e.date = date) && (e.meal == 'Lunch'));
});
let dinnerData = parsedData.filter(function (e) {
return ((e.date = date) && (e.meal == 'Dinner'));
});
let snacksData = parsedData.filter(function (e) {
return ((e.date = date) && (e.meal == 'Snacks'));
});
setMealPlannerData(JSON.parse(isDataAvailable))
setBreakfast(breakfastData)
setLunch(breakfastData)
setDinner(dinnerData)
setSnacks(snacksData)
} else {
setMealPlannerData([])
}
}
const childToParent = async(unique_id, meal, date) => {
const mealFiltered = mealPlannerData.filter(function (e) {
return e.unique_id != unique_id;
});
console.log(unique_id)
console.log(date)
if (meal === 'Breakfast') {
let breakfastData = mealFiltered.filter(function (e) {
return ((e.date = date) && (e.meal == 'Breakfast'));
});
console.log(breakfastData);
setBreakfast(breakfastData)
}
return (
<Container style={styles.background_general}>
<View>
{breakfast.map((p, i) => {
console.log(breakfast)
return (<>
<FoodItem meal={"Breakfast"} date={p.date} food={p.recipe_name} calories={p.calories} servings={p.servings} unique_id={p.unique_id} mealData={mealPlannerData} childToParent={childToParent}/>
<View style={{
borderBottomColor: 'rgba(0,0,0,0.1)',
borderBottomWidth: 1,
}}>
</View>
</>
)
})}
</View>
</Container>
}
}
And the FoodItem.js
const FoodItem = props => {
removeMeal = (unique_id, meal) => {
props.childToParent(unique_id, meal, props.date)
}
const renderRightActions = useCallback((progress, dragX) => {
const trans = dragX.interpolate({
inputRange: [-300, -160, 0],
outputRange: [0, 0, 160],
});
return (
<Animated.View
style={{
transform: [{ translateX: trans }],
}}
>
<LinearGradient
colors={["#6e269b", "#35184e"]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={{
flexDirection: "row",
width: 160,
height: "100%",
borderRadius: 20
}}
>
<RectButton style={{
justifyContent: "center",
alignItems: "center",
paddingHorizontal: 16,
flex: 1
}} onPress={() => {removeMeal(props.unique_id, props.meal) }}>
<View style={{ flexDirection: 'row' }}>
<Icon type="FontAwesome" name="trash" style={{ fontSize: 18, color: 'white', paddingRight: 10, marginTop: 2 }} />
<Text style={{ color: '#fff', fontWeight: 'bold', fontSize: 18 }}>
Remove
</Text>
</View>
</RectButton>
</LinearGradient>
</Animated.View>);
}, []);
return (
<View style={{
padding: 20
}}>
<Swipeable renderRightActions={renderRightActions}>
<View padding-6 row>
<View style={{ alignItems: "center" }}>
</View>
<View >
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>
{props.food}
</Text>
<View row marginT-8>
<View row>
<Text R14 color6D marginL-4>
{props.calories} cal
</Text>
</View>
<View row marginL-24>
<Text R14 color6D marginL-4>
{props.servings} servings
</Text>
</View>
</View>
</View>
</View>
</Swipeable>
</View>
)
}
Any help would be greatly appreciated!

How to change change and track boolean state of each element in an array

Im trying to make it so that when a TouchableHighlight is pressed in react native it goes from one colour to another. I have state that is set to false and changes when the button is pressed. However this changes the colour for all elements in the map rather than for each item individually. Is there a way to update the state for each element independently?
Here is my code:
function OnboardingVibes() {
const [pressed, setPressed] = useState(false);
return (
<View style={{marginTop: 40}}>
<Text style={{fontSize: 22, color: '#FFF', marginBottom: 16}}>Vibes</Text>
<View style={styles.buttonContainer}>
{vibes.map((vibe) => {
return (
<TouchableHighlight onPress={() => setPressed(true)} style={{backgroundColor: pressed ? '#DDD' : '#4D2C5B', margin: 4, borderRadius: 4}} key={`vibe-${vibe}`}>
<Text style={styles.vibeButton}>{vibe}</Text>
</TouchableHighlight>
)
})}
</View>
</View>
);
}
One way to do it is to move the state down so you could have individual states. When the state is true at the top-level, all child components will receive the same state.
function TouchableVibe({vibe}) {
const [pressed, setPressed] = useState(false);
return (
<TouchableHighlight
onPress={() => setPressed(true)}
style={{
backgroundColor: pressed ? "#DDD" : "#4D2C5B",
margin: 4,
borderRadius: 4,
}}
>
<Text style={styles.vibeButton}>{vibe}</Text>
</TouchableHighlight>
);
}
function OnboardingVibes() {
return (
<View style={{ marginTop: 40 }}>
<Text style={{ fontSize: 22, color: "#FFF", marginBottom: 16 }}>
Vibes
</Text>
<View style={styles.buttonContainer}>
{vibes.map((vibe) => (
<TouchableVibe key={`vibe-${vibe}`} vibe={vibe} />
))}
</View>
</View>
);
}
const [pressed, setPressed] = useState(vibes.map(e=>false));
{vibes.map((vibe, index) => {
return (
<TouchableHighlight onPress={() => {
let new_Pressed =vibes.map(e=>false)
new_pressed[index]=true;
setPressed(new_pressed);
}}
style={{backgroundColor: pressed[index]
? '#DDD'
: '#4D2C5B',
margin: 4, borderRadius: 4}} key={`vibe-${vibe}`}>
<Text style={styles.vibeButton}>{vibe}</Text>
</TouchableHighlight>
)
})}
Instead of passing in a boolean to the state, pass in the id/vibe instead, and then in your conditional logic within the map you can determine if that single item is the same as the one you've clicked.
function OnboardingVibes() {
const [pressed, setPressed] = useState('');
return (
<View style={{marginTop: 40}}>
<Text style={{fontSize: 22, color: '#FFF', marginBottom: 16}}>Vibes</Text>
<View style={styles.buttonContainer}>
{vibes.map((vibe) => {
return (
<TouchableHighlight onPress={() => setPressed(vibe)} style={{backgroundColor: pressed === vibe ? '#DDD' : '#4D2C5B', margin: 4, borderRadius: 4}} key={`vibe-${vibe}`}>
<Text style={styles.vibeButton}>{vibe}</Text>
</TouchableHighlight>
)
})}
</View>
</View>
);
}

Page slider not working On Android, works fine in iOS

The code below shows how all the functions are implemented
On iOS everything works fine, the button changes slide, the dots on the bottom change state based on the page and on the last page it displays a signup button,
On Android, the button works only on the first page, the last page doesnt show the signup button, and next button doesnt work on the second page!
export default function introScreen({ navigation }) {
const [sliderState, setSliderState] = useState({ currentPage: 0 });
const scrollRef = useRef();
const { width, height } = Dimensions.get('window')
const notchSize = StatusBar.currentHeight
const setSliderPage = (event: any) => {
const { currentPage } = sliderState;
const { x } = event.nativeEvent.contentOffset;
const indexOfNextScreen = Math.floor(x / width);
if (indexOfNextScreen !== currentPage) {
setSliderState({
...sliderState,
currentPage: indexOfNextScreen,
});
}
};
const { currentPage: pageIndex } = sliderState;
const onPressTouch = () => {
scrollRef.current?.scrollTo({
x: width*(pageIndex+1),
animated: true,
});
}
return (
<>
<StatusBar hidden />
<SafeAreaView style={{ flex: 1, backgroundColor:'black' }}>
<ScrollView
style={{ flex: 1 }}
horizontal={true}
scrollEventThrottle={16}
pagingEnabled={true}
showsHorizontalScrollIndicator={false}
onScroll={(event: any) => {
setSliderPage(event);
}}
ref={scrollRef}
>
<View style={{ width, height, alignItems: 'center', }}>
<Image source={require('../../assets/images/Intorduction/1.png')} style={styles.imageStyle} />
<BlurView tint={'dark'} intensity={70} style={{width:'80%',borderRadius:10, marginTop:10}}>
<Text style={[styles.textStyle,{color:'rgb(255, 190, 46)'}]}bla bla</Text>
</BlurView>
</View>
<View style={{ width, height, alignItems: 'center' }}>
<Image source={require('../../assets/images/Intorduction/2.png')} style={styles.imageStyle} />
<BlurView tint={'dark'} intensity={70} style={{width:'80%',borderRadius:10, marginTop:10}}>
<Text style={[styles.textStyle,{color:'rgb(255, 190, 46)'}]}>bla bla</Text>
</BlurView>
</View>
<View style={{ width, height, alignItems: 'center' }}>
<Image source={require('../../assets/images/Intorduction/3.png')} style={styles.imageStyle} />
<BlurView tint={'light'} intensity={70} style={{width:'80%',borderRadius:10, marginTop:10}}>
<Text style={[styles.textStyle,{color:'rgb(241, 250, 238)'}]}>bla bla</Text>
</BlurView>
</View>
</ScrollView>
{pageIndex != 2 ?
<View style={styles.paginationWrapper}>
{Array.from(Array(3).keys()).map((key, index) => (
<View style={[styles.paginationDots, { opacity: pageIndex === index ? 1 : 0.2 }]} key={index} />
))}
</View>
:
<></>
}
{pageIndex != 2 ?
<BlurView tint={'dark'} intensity={70} style={styles.nextButton}>
<TouchableOpacity style={{flex:1, justifyContent:'center', alignItems:'center'}} onPress={onPressTouch} >
<Text style={{color:'rgb(241, 250, 238)',fontFamily: 'poiret-one', fontSize:25}}>
Next
</Text>
</TouchableOpacity>
</BlurView>
:
<BlurView tint={'light'} intensity={70} style={styles.signUpButton}>
<TouchableOpacity style={{flex:1, justifyContent:'center', alignItems:'center'}} onPress={() =>navigation.navigate('Login')} >
<Text style={{color:'black',fontFamily: 'poiret-one', fontSize:25}}>
Sign Up
</Text>
</TouchableOpacity>
</BlurView>
}
</SafeAreaView>
</>
);
}
I have narrowed down the problem to the width and the 'event.nativeEvent.contentOffset', the returning number is close to 1 but it is (0.9), therefor math.floor was giving 0 as the index number,
I have changed Math.floor to Math.round and it is working perfectly fine,
If anyone wants a Introduction Slider for their app they can use this

How change the styling of dynamically generated JSX via a button click in React Native

I am generating JSX code based on an array values that I get from a backend API. As shown in the image below I am generating those boxes based on the length of the array. What I want is when I click on any of those boxes the background colour changes.
I want these boxes to behave like a radio button, so only one box has a different background colour at a time. The array name is "hasMultipleWeights".
I only included the relevant parts of the code ...
const ProductDetailsScreen = (props) => {
const productId = props.navigation.getParam("productId");
const selectedProduct = useSelector((state) =>
state.products.products.find((prod) => prod.id === productId)
);
const productsMultipleWeights = useSelector(
(state) => state.products.productsMultipleWeights
);
var hasMultipleWeights = productsMultipleWeights.find(
(prod) => Object.keys(prod)[0] == selectedProduct.id
);
if (hasMultipleWeights) {
hasMultipleWeights = hasMultipleWeights[Object.keys(hasMultipleWeights)[0]];
}
return (
<ScrollView style={{}}>
<View style={styles.screen}>
{hasMultipleWeights && (
<View style={{ alignItems: "center" }}>
<ScrollView
horizontal
contentContainerStyle={{ padding: 2 }}
showsHorizontalScrollIndicator={false}
>
{hasMultipleWeights.map((item) => (
<TouchableOpacity
key={item.id}
onPress={() => {}}
style={{
...styles.productOptions,
backgroundColor: 'white',
}}
>
<Text style={styles.productWeightVolumUnit}>
<Text style={styles.productWeightVolumeValue}>
{NS(item.weight, "Arabic")}
</Text>
{" "}
{selectedProduct.weightVolumeUnit}
</Text>
<MaterialCommunityIcons
name={
selectedProduct.weightVolumeUnit === "كغ"
? "weight-kilogram"
: selectedProduct.weightVolumeUnit === "مل"
? "water"
: "weight-gram"
}
size={26}
color="grey"
style={styles.weightIcon}
/>
</TouchableOpacity>
))}
</ScrollView>
</View>
)}
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
productOptions: {
shadowColor: "black",
shadowOpacity: 0.26,
elevation: 5,
borderRadius: 10,
backgroundColor: "white",
width: 85,
height: 65,
marginHorizontal: 6,
alignItems: "center",
justifyContent: "center",
shadowRadius: 2,
shadowOffset: { width: 0, height: 1 },
},
});
For changing the color dynamically you have to use state. So, create a new state to check the button that is "checked", you change it in your onPress method and then make the validation.
const ProductDetailsScreen = (props) => {
const [checkedButton, setCheckedButton] = React.useState('')
const productId = props.navigation.getParam("productId");
const selectedProduct = useSelector((state) =>
state.products.products.find((prod) => prod.id === productId)
);
const productsMultipleWeights = useSelector(
(state) => state.products.productsMultipleWeights
);
var hasMultipleWeights = productsMultipleWeights.find(
(prod) => Object.keys(prod)[0] == selectedProduct.id
);
if (hasMultipleWeights) {
hasMultipleWeights = hasMultipleWeights[Object.keys(hasMultipleWeights)[0]];
}
return (
<ScrollView style={{}}>
<View style={styles.screen}>
{hasMultipleWeights && (
<View style={{ alignItems: "center" }}>
<ScrollView
horizontal
contentContainerStyle={{ padding: 2 }}
showsHorizontalScrollIndicator={false}
>
{hasMultipleWeights.map((item) => (
<TouchableOpacity
key={item.id}
onPress={() => setCheckedButton(item.id)}
style={{
...styles.productOptions,
backgroundColor: checkedButton === item.id ? "grey" : "white",
}}
>
<Text style={styles.productWeightVolumUnit}>
<Text style={styles.productWeightVolumeValue}>
{NS(item.weight, "Arabic")}
</Text>
{" "}
{selectedProduct.weightVolumeUnit}
</Text>
<MaterialCommunityIcons
name={
selectedProduct.weightVolumeUnit === "كغ"
? "weight-kilogram"
: selectedProduct.weightVolumeUnit === "مل"
? "water"
: "weight-gram"
}
size={26}
color="grey"
style={styles.weightIcon}
/>
</TouchableOpacity>
))}
</ScrollView>
</View>
)}
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
productOptions: {
shadowColor: "black",
shadowOpacity: 0.26,
elevation: 5,
borderRadius: 10,
backgroundColor: "white",
width: 85,
height: 65,
marginHorizontal: 6,
alignItems: "center",
justifyContent: "center",
shadowRadius: 2,
shadowOffset: { width: 0, height: 1 },
},
});
Seems like you need to create checkedId state
const [ checkedId, setCheckedId ] = useState('')
useEffect(() =>
// set first box to red at first render
hasMultipleWeights && setCheckedId(hasMultipleWeights[0].id) ,[ hasMultipleWeights ])
...
<TouchableOpacity
key={item.id}
onPress={() =>setCheckedId(item.id)}
style={{
...styles.productOptions,
backgroundColor: item.id == checkedId ? 'red' : 'white',
}}
>

Categories

Resources