RN checkbox as card and multi select - javascript

I've to select one or two cards from a list of cards , where on tap of each card / checkbox , that card gets highlighted (and is selected). Each card has checkbox on it, which shows that particular card through which selection is made. You can re-tap on the same checkbox to unselect it.
I'm pretty new to react native and confused how to achieve this functionality. Here's the code for reference.
import React, { Component } from 'react';
import {View, Image, StyleSheet} from 'react-native';
import { Container, Content, ListItem, CheckBox, Text, Body } from 'native-base';
export default class Career extends Component {
topics = ['abc','def', 'ghi', 'jkl']
render() {
const extract = this.topics.map((topic, i) => {
return(
<View style={styles.cardContainer}>
<Image style={{width:50, height:50}} source={require('../../assets/images/idcLogo.png')}/>
<CheckBox checked={false}></CheckBox>
<Text>{topic}</Text>
</View>
)
});
return (
<Container>
<Content>
<View style={styles.mainContainer}>
{extract}
</View>
</Content>
</Container>
);
}
}
const styles = StyleSheet.create({
cardContainer: {
borderRadius:5,
borderColor:"#ccc",
borderWidth:2,
justifyContent:'center',
alignItems:'center',
width:'50%',
margin:5
},
mainContainer:{
justifyContent:'center',
width:'100%',
alignItems:'center',
flex:1
}
})
Please let me know if this you need any other information on this. Thanks in advance

I would change the <View style={styles.cardContainer}></View> into <TouchableOpacity style={styles.cardContainer}> then I'll add a function to monitor the changes of the checked status for the button.
I'll add this function before the render function
handleOnTap = (topic) => {
this.setState(prevState => ({ [topic]: !prevState[topic], });
}
<Checkbox onPress={() => this.handleOnTap(topic)} checked={!!this.state[topic]} />
Don't forget to add a key generating elements via this.topics.map; <TouchableOpacity style={styles.cardContainer} key={topic-${i}}>
Hope that helps

Related

React Native Firebase Firestore data fetching with empty spaces

I have created 3 documents in Firestore database, each document has different data.
but When I add different data on different document ids then I am getting blank spaces, and those spaces are generated automatically for other document ids which I already created previously.
Document 1 should be shown on First screen and document 2 should show on screen two. I mean each document's data should show on its own screen. please check the image link below-
First Screen
import React, { useState, useEffect } from 'react';
import {View, Button, Text, FlatList, StyleSheet, Pressable, TouchableOpacity} from 'react-native'
import {firebase} from '../config';
const Testing = ({ navigation }) =>{
const [users, setUsers] = useState([]);
const todoRef = firebase.firestore().collection('testing');
useEffect(() => {
todoRef.onSnapshot(
querySnapshot => {
const users = []
querySnapshot.forEach((doc) => {
const { One, Two, Three
} = doc.data()
users.push({
id: doc.id,
One, Two, Three
})
})
setUsers(users)
}
)
}, [])
return (
<View style={{ flex:1,}}>
<FlatList
style={{height: '100%'}}
data={users}
numColumns={1}
renderItem={({item}) => (
<Pressable >
<View style={styles.viewOne}>
<View>
<Text style={[styles.card, styles.title]}>{item.One}</Text>
<Text style={styles.text}>{item.Two}</Text>
<Text style={styles.text}>{item.Three}</Text>
</View>
</View>
</Pressable>
)} />
</View>
);}
export default Testing;
*Second Screen*
import React, { useState, useEffect } from 'react';
import {View, Button, Text, FlatList, StyleSheet, Pressable, TouchableOpacity} from 'react-native'
import {firebase} from '../config';
const TestingDocs = ({ navigation }) =>{
const [users, setUsers] = useState([]);
const todoRef = firebase.firestore().collection('testing');
useEffect(() => {
todoRef.onSnapshot(
querySnapshot => {
const users = []
querySnapshot.forEach((doc) => {
const { DocsOne, DocsTwo, DocsThree,
} = doc.data()
users.push({
id: doc.id,
DocsOne, DocsTwo, DocsThree,
})
})
setUsers(users)
}
)
}, [])
return (
<View style={{ flex:1,}}>
<FlatList
style={{height: '100%'}}
data={users}
numColumns={1}
renderItem={({item}) => (
<Pressable >
<View style={styles.viewOne}>
<View>
<Text style={[styles.card, styles.title]}>{item.DocsOne}</Text>
<Text style={styles.text}>{item.DocsTwo}</Text>
<Text style={styles.text}>{item.DocsThree}</Text>
</View>
</View>
</Pressable>
)} />
</View>
);}
export default TestingDocs;
You must have seen this Answer on your another Post :
It looks like you've incomplete or "optional" data in your backend. If
you don't want to render empty fields you can conditionally render
them.
For the users data that is missing both properties you can filter
the data prop.
Example:
<FlatList
data={users.filter(({ One, five }) => One || five)}
renderItem={({ item }) => (
<View style={{ .... }}>
{item.One && <Text>ID: {item.One}</Text>}
{item.five && <Text>Name: {item.five}</Text>}
</View>
)}
/>
You can also refer to this Answer:
Its as a result of performance issues with the FlatList component but
you can add the following props to your FlatList Component, it would
help solve the problem. They are:
i. removeClippedSubviews.
Set this to true, it comes with a default of false.
ii. windowSize. Set this to a number like say 30
iii. maxToRenderPerBatch. This controls the number of items rendered per batch, which is the next chunk of items rendered on every
scroll.
<FlatList
data={this.state.contacts}
removeClippedSubviews={true}
maxToRenderPerBatch={60}
windowSize={30}
ListHeaderComponent={headerComponent}
contentContainerStyle={{ paddingBottom: 10 }}
renderItem={({ item }) => (
<View>
{item}
</View>
)}
numColumns={1}
keyExtractor={(item, index) => String(index)}
/>
For more information, you can refer to the blog which explains how to use react hooks with firebase firestore.

how to update a component from another child component in ReactNative

Right. I've been googling for days and can't seem to find an example that works and that I understand.
I've currently got three components, ButtonComponent, SecondButton, and TextComponent.
I already have it such that tapping Button can update State and thus change the text in TextComponent (if i set setState to the text string on line 39).
How can I change it so that it will change to a string of text that I can set from the button itself rather than the function fired by the button, so that SecondButton can fire the same function as Button, but update the text to something different.
I figure it must be a small tweak to onPress? but everything I try keeps complaining about objects and things being undefined.
Thanks.
import { setStatusBarNetworkActivityIndicatorVisible, StatusBar } from 'expo-status-bar';
import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
function ButtonComponent({changeText}) {
console.log(`2. ${changeText} from inside Button Component`)
return(
<Button title="change text" onPress={changeText} />
)
}
function SecondButton({changeText}){
return(
<Button title="change text again" onPress={changeText} />
)
}
function TextComponent({text}) {
console.log(`3. ${text} from inside Text Component`) //
return (
<View>
<Text style={styles.text}>{text}</Text>
</View>
)
}
export default function App() {
console.log('1 .start')
const [text, setText] = useState('default text'); // declared in the screen
const changeText = ({newtext}) => {
setText(newtext)
console.log(`4. ${text} just after changeText`)
}
return(
<View style={styles.container}>
<ButtonComponent changeText={changeText}/>
<SecondButton changeText={changeText}/>
<TextComponent text={text}/>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
text: {
color: 'red',
}
});
function SecondButton({changeText}){
return(
<Button
title="change text again"
onPress={() => changeText( { newtext: "different string" })}
/>
)
}

React native useState and return statement not working together

Here whenever i click the icon it doesnt show anything. It supposed to be showing some text and when clicked again it should hide the text. Im using react native.
import React, { useState } from 'react';
import { View, Text, StyleSheet, Button, Image, TouchableOpacity} from 'react-native';
import FontAwesome from 'react-native-vector-icons/FontAwesome';
export default function Edit(props, { navigation }) {
const [slide, setSlide] = useState(false);
const toggle = () => {
setSlide(!slide);
console.log('clicked');
return (
<View>
<Text>random</Text>
<Text>random</Text>
</View>
);
}
return (
<View>
<FontAwesome name="sliders" size={30} color="#000" onPress={() => toggle()}/>
</View>
}
After testing the only thing it shows is the console.log('clicked') message. It does not display anything else. Also the icon displays normally. Everything is working except the and the content in those tags.
Rather than returning the View from your toggle function, you actually need to display that view your view hierarchy (eg what is returned from your component).
I've demonstrated in the example by using a ternary expression -- if slide is true, it gets shown, otherwise it does not.
export default function Edit(props, { navigation }) {
const [slide, setSlide] = useState(false);
const toggle = () => {
setSlide(!slide);
console.log('clicked');
}
return (
<View>
<FontAwesome name="sliders" size={30} color="#000" onPress={() => toggle()}/>
{slide ? <View>
<Text>random</Text>
<Text>random</Text>
</View> : null}
</View>
);
}
Snack example: https://snack.expo.io/7lVezwWs7

React Native: Passing useState() data to unrelated screens

Explanation: I am creating a fitness app, my fitness app has a component called WorkoutTimer that connects to the workout screen, and that screen is accessed via the HomeScreen. Inside the WorkoutTimer, I have an exerciseCount useState() that counts every time the timer does a complete loop (onto the next exercise). I have a different screen called StatsScreen which is accessed via the HomeScreen tab that I plan to display (and save) the number of exercises completed.
What I've done: I have quite literally spent all day researching around this, but it seems a bit harder with unrelated screens. I saw I might have to use useContext() but it seemed super difficult. I am fairly new to react native so I am trying my best haha! I have attached the code for each screen I think is needed, and attached a screenshot of my homeScreen tab so you can get a feel of how my application works.
WorkoutTimer.js
import React, { useState, useEffect, useRef } from "react";
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Button,
Animated,
Image,
SafeAreaView,
} from "react-native";
import { CountdownCircleTimer } from "react-native-countdown-circle-timer";
import { Colors } from "../colors/Colors";
export default function WorkoutTimer() {
const [count, setCount] = useState(1);
const [exerciseCount, setExerciseCount] = useState(0);
const [workoutCount, setWorkoutCount] = useState(0);
const exercise = new Array(21);
exercise[1] = require("../assets/FR1.png");
exercise[2] = require("../assets/FR2.png");
exercise[3] = require("../assets/FR3.png");
exercise[4] = require("../assets/FR4.png");
exercise[5] = require("../assets/FR5.png");
exercise[6] = require("../assets/FR6.png");
exercise[7] = require("../assets/FR7.png");
exercise[8] = require("../assets/FR8.png");
exercise[9] = require("../assets/S1.png");
exercise[10] = require("../assets/S2.png");
exercise[11] = require("../assets/S3.png");
exercise[12] = require("../assets/S4.png");
exercise[13] = require("../assets/S5.png");
exercise[14] = require("../assets/S6.png");
exercise[15] = require("../assets/S7.png");
exercise[16] = require("../assets/S8.png");
exercise[17] = require("../assets/S9.png");
exercise[18] = require("../assets/S10.png");
exercise[19] = require("../assets/S11.png");
exercise[20] = require("../assets/S12.png");
exercise[21] = require("../assets/S13.png");
return (
<View style={styles.container}>
<View style={styles.timerCont}>
<CountdownCircleTimer
isPlaying
duration={45}
size={240}
colors={"#7B4FFF"}
onComplete={() => {
setCount((prevState) => prevState + 1);
setExerciseCount((prevState) => prevState + 1);
if (count == 21) {
return [false, 0];
}
return [(true, 1000)]; // repeat animation for one second
}}
>
{({ remainingTime, animatedColor }) => (
<View>
<Image
source={exercise[count]}
style={{
width: 150,
height: 150,
}}
/>
<View style={styles.timeOutside}>
<Animated.Text
style={{
color: animatedColor,
fontSize: 18,
position: "absolute",
marginTop: 67,
marginLeft: 35,
}}
>
{remainingTime}
</Animated.Text>
<Text style={styles.value}>seconds</Text>
</View>
</View>
)}
</CountdownCircleTimer>
</View>
</View>
);
}
const styles = StyleSheet.create({})
WorkoutScreen.js
import React, { useState } from "react";
import { StyleSheet, Text, View } from "react-native";
import WorkoutTimer from "../components/WorkoutTimer";
export default function WorkoutScreen() {
return (
<View style={styles.container}>
<WorkoutTimer />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
HomeScreen.js
import React from "react";
import { StyleSheet, Text, View, SafeAreaView, Button } from "react-native";
import { TouchableOpacity } from "react-native-gesture-handler";
import { AntDesign } from "#expo/vector-icons";
import { Colors } from "../colors/Colors";
export default function HomeScreen({ navigation }) {
return (
<SafeAreaView style={styles.container}>
<Text style={styles.pageRef}>SUMMARY</Text>
<Text style={styles.heading}>STRETCH & ROLL</Text>
<View style={styles.content}>
<TouchableOpacity
style={styles.timerDefault}
onPress={() => navigation.navigate("WorkoutScreen")}
>
<Button title="START WORKOUT" color={Colors.primary} />
</TouchableOpacity>
<TouchableOpacity
style={styles.statContainer}
onPress={() => navigation.navigate("StatsScreen")}
>
<AntDesign name="barschart" size={18} color={Colors.primary} />
<Text style={{ color: Colors.primary }}>Statistics</Text>
<AntDesign name="book" size={18} color={Colors.primary} />
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({})
StatsScreen.js
import React from "react";
import { StyleSheet, Text, View } from "react-native";
import { exerciseCount, workoutCount } from "../components/WorkoutTimer";
export default function StatsScreen() {
return (
<View style={styles.container}>
<Text display={exerciseCount} style={styles.exerciseText}>
{exerciseCount}
</Text>
<Text display={workoutCount} style={styles.workoutText}>
{workoutCount}
</Text>
</View>
);
}
const styles = StyleSheet.create({});
Home Screen Image
As far as I can tell, you're almost there! You're trying to get your 2 state
variables from the WorkoutTimer like this:
import { exerciseCount, workoutCount } from "../components/WorkoutTimer";
Unfortunatly this won't work :( . These two variables change throughout your
App's life-time and that kinda makes them "special".
In React, these kinds of variables need to be declared in a parent component
and passed along to all children, which are interested in them.
So in your current Setup you have a parent child relationship like:
HomeScreen -> WorkoutScreen -> WorkoutTimer.
If you move the variables to HomeScreen (HomeScreen.js)
export default function HomeScreen({ navigation }) {
const [exerciseCount, setExerciseCount] = useState(0);
const [workoutCount, setWorkoutCount] = useState(0);
you can then pass them along to WorkoutScreen or StatsScreen with something
like:
navigation.navigate("WorkoutScreen", { exerciseCount })
navigation.navigate("StatsScreen", { exerciseCount })
You'll probably have to read up on react-navigation's documentation for .navigate I'm not sure I remember this correctly.
In order to read the variable you can then:
export default function WorkoutScreen({ navigation }) {
const exerciseCount = navigation.getParam(exerciseCount);
return (
<View style={styles.container}>
<WorkoutTimer exerciseCount={exerciseCount} />
</View>
);
}
and finally show it in the WorkoutTimer:
export default function WorkoutTimer({ exerciseCount }) {
Of course that's just part of the solution, since you'll also have to pass
along a way to update your variables (setExerciseCount and setWorkoutCount).
I encourage you to read through the links I posted and try to get this to work.
After you've accumulated a few of these stateful variables, you might also want to look at Redux, but this is a bit much for now.
Your app looks cool, keep at it!
I ended up solving this problem with useContext if anyone is curious, it was hard to solve initially. But once I got my head around it, it wasn't too difficult to understand.
I created another file called exerciseContext with this code:
import React, { useState, createContext } from "react";
const ExerciseContext = createContext([{}, () => {}]);
const ExerciseProvider = (props) => {
const [state, setState] = useState(0);
//{ exerciseCount: 0, workoutCount: 0 }
return (
<ExerciseContext.Provider value={[state, setState]}>
{props.children}
</ExerciseContext.Provider>
);
};
export { ExerciseContext, ExerciseProvider };
and in App.js I used ExerciseProvider which allowed me to pass the data over the screens.
if (fontsLoaded) {
return (
<ExerciseProvider>
<NavigationContainer>
<MyTabs />
</NavigationContainer>
</ExerciseProvider>
);
} else {
return (
<AppLoading startAsync={getFonts} onFinish={() => setFontsLoaded(true)} />
);
}
}
I could call it with:
import { ExerciseContext } from "../components/ExerciseContext";
and
const [exerciseCount, setExerciseCount] = useContext(ExerciseContext);
This meant I could change the state too! Boom, solved! If anyone needs an explanation, let me know!
I think you have to use Mobx or Redux for state management. That will be more productive for you instead built-in state.

Adjacent JSX elements must be wrapped in an enclosing tag React Native

I'm a beginner in React Native trying to test out TouchableOpacity. I keep getting this error code 'Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...? (16:4)'
The issue seems to be at the opening TouchableOpacity tag.
I've already tried putting fragments around it but it didn't work does anyone know how I fix this??
import React from 'react';
import { Text, StyleSheet, View, Button, TouchableOpacity } from 'react-
native';
const HomeScreen = () => {
return (
<View>
<Text style={styles.text}>Sup boiz</Text>
<Button
onPress={() => console.log('Button pressed')}
title="Go to components demo"
/>
<TouchableOpacity onPress={ () => console.log('List Pressed')>
<Text>Go to List demo</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
text: {
fontSize: 30
}
});
export default HomeScreen;
<TouchableOpacity onPress={ () => console.log('List Pressed')}>
<Text>Go to List demo</Text>
</TouchableOpacity>
Simple syntax error. It should be onPress={ () => console.log('List Pressed')}
You missed }

Categories