Make Elements have full width - javascript

I am new to CSS skills.
I didn't learn much about it.
I have a question about how to make an element have full width.
I added my code down below, but the simplest way I tried didn't work which is width: '100%'.
I have a code in react native, so components are nested in order I put. The higher code is a parent of code right down to it.
I would like elements in RideCard.js, each ride card, to have expand fully next to DateDay.js. I could have seen that once I removed flexDirection: row in oneDayContainer in MonthBody.js, the elements expanded fully.
But I would like to keep the design.
Thanks in advance.
MonthBody > DateDay + RideList >
MonthBody.js
import { StyleSheet } from "react-native";
import { View } from "react-native";
import { useFirestoreContext } from "../../contexts/FirestoreContext";
import { DateDay } from "./DateDay";
import { RideList } from "./RideList";
export const MonthBody = ({ monthYear }) => {
const { rides } =
useFirestoreContext();
return (
<View style={styles.monthBodyContainer}>
{Object.keys(rides[monthYear]).map((dateDay, j) => {
return (
<View style={styles.oneDayContainer}>
<DateDay dateDay={dateDay} />
<RideList monthYear={monthYear} dateDay={dateDay} />
</View>
);d
})}
</View>
);
}
const styles = StyleSheet.create({
monthBodyContainer: {
display: "flex",
flexDirection: "column",
},
oneDayContainer: {
display: "flex",
flexDirection: "row",
alignItems: "flex-start",
},
});
DateDay.js
import { StyleSheet, Text, View } from "react-native";
export const DateDay = ({dateDay}) => {
return (
<View style={styles.dateDayContainer}>
<Text style={styles.dayText}>{dateDay.split("-")[1]}</Text>
<Text style={styles.dateText}>{dateDay.split("-")[0]}</Text>
</View>
);
};
const styles = StyleSheet.create({
dateDayContainer: {
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
width: 50,
marginRight: 20,
marginTop: 10,
},
dateText: {
fontSize: 16,
textAlign: "center",
},
dayText: {
fontSize: 12,
textAlign: "center",
},
});
RideList.js
import { StyleSheet, Text, View } from "react-native";
import { COLOR } from "../../assets/variables";
import { useFirestoreContext } from "../../contexts/FirestoreContext";
import { RideCard } from "./RideCard";
export const RideList = ({ monthYear, dateDay }) => {
const { rides } = useFirestoreContext();
return (
<View style={styles.rideList}>
{rides[monthYear][dateDay].map((ride, k) => {
// return <RideCard key={k} ride={ride} />;
return <RideCard key={k} ride={ride} />;
})}
</View>
);
};
const styles = StyleSheet.create({
rideList: {
marginBottom: 5,
},
});
RideCard.js
import { StyleSheet, Text, View } from "react-native";
import { COLOR } from "../../assets/variables";
export const RideCard = ({ ride }) => {
console.log("RideCard", ride);
return (
<View
style={[
styles.container,
ride.boardType === "NEED"
? { backgroundColor: COLOR.lightGreen, borderWidth: .3, borderColor: COLOR.green }
: { backgroundColor: COLOR.lightBlue, borderWidth: .3, borderColor: COLOR.blue },
]}
>
<View style={styles.places}>
<Text style={styles.placeText}>{ride.cityFrom}</Text>
<Text> - </Text>
<Text style={styles.placeText}>{ride.cityTo}</Text>
</View>
<View>
<Text style={styles.dateText}>
{ride.leavingHour}:{ride.leavingMinutes}
</Text>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
padding: 10,
marginBottom: 5,
borderRadius: 10,
},
places: {
display: "flex",
flexDirection: "row",
alignItems: "center",
marginBottom: 5,
},
});

On the CardList styles you can add flex: 1 to the rideList.
const styles = StyleSheet.create({
rideList: {
marginBottom: 5,
flex: 1,
},
});

Related

How we can give auto height to FlatList based on its list items content in React Native

I am using FlatList in my component which is working fine. All is wanted is that my entire screen should have an automatic height to it and FlatList contents never does out of the screen height.
Also, the height of FlatList should be changed based on content/items in it rather than giving any fixed height.
How I can be acheived both cases like automatic screen height and auto height of FlatList content?
Code:
import React, { useState, useEffect } from 'react';
import {
View,
StyleSheet,
useWindowDimensions,
Text,
FlatList,
SafeAreaView,
TouchableOpacity,
} from 'react-native';
import { LinearGradient as LinearGradientView } from 'expo-linear-gradient';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ActivityIndicator, ThemeProvider } from 'react-native-paper';
import { ScrollView } from 'react-native-gesture-handler';
import { useIsFocused, useNavigation } from '#react-navigation/native';
import Svg, { Path } from 'react-native-svg';
import { BASE_GRADIENT_HEAVY } from '../rooms/Background';
import { useResolution } from '../browse/useResolution';
import { OnboardingNavigationProp } from '../navigation/LinkingConfiguration';
import { LIGHT_THEME } from '../Theme';
import { OnboardingBack } from './OnboardingBack';
import {
useOnboardingYearsOfExperiencePage,
useOnboardingYearsOfExperienceSubmit,
} from './useOnboardingYearsOfExperiencePage';
export function OnboardingYearsOfExperience({ route }: { route?: any }) {
const { height } = useWindowDimensions();
const { top: safeAreaTop } = useSafeAreaInsets();
const [selectedId, setSelectedId] = useState<{ id: string }>();
const [role_id, setRoleId] = useState<number>();
const { navigate } =
useNavigation<OnboardingNavigationProp<'OnboardingConfirmAllDetails'>>();
const parentUrl = route?.params.result.onboarding._links;
const initialUrl = parentUrl.onboarding_years_of_experience.href;
const onboardingUrl = parentUrl.self.href;
useEffect(() => {
setRoleId(route?.params.role_id);
}, []);
const isFocused = useIsFocused();
const { contentType } = useResolution();
const {
data: result,
isLoading,
error,
} = useOnboardingYearsOfExperiencePage(initialUrl, contentType, role_id, {
enabled: isFocused,
notifyOnChangeProps: ['data', 'isLoading', 'error'],
});
const {
mutateAsync: updateYearsOfExperience,
isLoading: isUpdatingYearsOfExperience,
error: yearsOfExperienceUpdateError,
} = useOnboardingYearsOfExperienceSubmit(onboardingUrl);
const Arrow = ({ style }: { style: object }) => {
return (
<Svg width="7" height="11" viewBox="0 0 7 11" fill="none" style={style}>
<Path
d="M6.28711 5.53931C6.28711 5.31649 6.19783 5.12476 6.02452 4.95376L1.9911 1.07251C1.85455 0.937781 1.68649 0.865234 1.48692 0.865234C1.07728 0.865234 0.751664 1.18651 0.751664 1.58552C0.751664 1.78243 0.830441 1.96898 0.977493 2.11407L4.54875 5.53413L0.977492 8.95937C0.835692 9.10446 0.751663 9.28583 0.751662 9.48792C0.751662 9.88693 1.07728 10.2082 1.48692 10.2082C1.68649 10.2082 1.85455 10.1357 1.99635 10.0009L6.02452 6.11968C6.20308 5.93832 6.28711 5.75695 6.28711 5.53931Z"
fill="#4D4D4D"
/>
</Svg>
);
};
const Item = ({
item,
onPress,
}: {
item?: { id: string; title: string };
onPress: () => void;
}) => (
<TouchableOpacity onPress={onPress}>
<Text
style={{
color: '#4D4D4D',
fontFamily: 'Inter_400Regular',
fontStyle: 'normal',
fontWeight: '400',
fontSize: 16,
lineHeight: 32,
padding: 3,
margin: 2,
}}
>
{item?.title}
</Text>
</TouchableOpacity>
);
const renderItem = ({ item }: { item: { id: string; title: string } }) => {
return (
<React.Fragment>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
borderRadius: 5,
backgroundColor:
selectedId?.id === item?.id ? '#F2F2F2' : 'transparent',
}}
>
<View style={{ width: '90%' }}>
<Item
item={item}
onPress={() => {
setSelectedId({ id: item.id });
updateYearsOfExperience({ id: item.id, role_id })
.then((result) => {
navigate('Onboarding', {
screen: 'OnboardingConfirmAllDetails',
params: { result },
});
})
.catch(() => {});
}}
/>
</View>
<View style={{ width: '10%' }}>
<Arrow style={{ position: 'absolute', top: 16, right: 10 }} />
</View>
</View>
</React.Fragment>
);
};
return (
<ThemeProvider theme={LIGHT_THEME}>
<View style={{ height: safeAreaTop }} />
<View style={styles.topHeader}>
<LinearGradientView
{...BASE_GRADIENT_HEAVY}
style={[styles.gradiantStyle]}
/>
</View>
<View style={styles.innerContainer}>
<ScrollView
contentContainerStyle={{
marginHorizontal: 'auto',
alignSelf: 'center',
width: '100%',
backgroundColor: '#ffffff',
height: '100%',
}}
>
<OnboardingBack
style={{
left: -10,
}}
/>
<Text style={styles.topHeadline}>
How many years of experience do you have?
</Text>
<Text style={styles.middleHeadline}>
Jump-start the conversation by sharing your years of experience
within healthcare.
</Text>
{isLoading || isUpdatingYearsOfExperience ? (
<ActivityIndicator size="large" />
) : (
<SafeAreaView>
<FlatList
contentContainerStyle={{ flexGrow: 1 }}
data={Object.values(
result!['years_of_experiences']['years_of_experiences_list']
)}
renderItem={renderItem}
keyExtractor={(item) => item.id}
extraData={selectedId}
style={{
borderWidth: 1,
borderStyle: 'solid',
borderColor: '#D7D7D7',
borderRadius: 5,
padding: 12,
height: '27%',
}}
ListEmptyComponent={
<View>
<Text>No data found</Text>
</View>
}
/>
</SafeAreaView>
)}
</ScrollView>
</View>
</ThemeProvider>
);
}
const styles = StyleSheet.create({
innerContainer: {
display: 'flex',
position: 'relative',
backgroundColor: 'white',
padding: 18,
},
topHeader: {
backgroundColor: '#e5dede',
padding: 0,
width: '100%',
},
topHeadline: {
fontSize: 24,
fontFamily: 'CircularStd_Medium',
fontStyle: 'normal',
fontWeight: '500',
color: '#222222',
marginTop: 40.6,
marginBottom: 14.6,
display: 'flex',
alignItems: 'center',
lineHeight: 32,
},
middleHeadline: {
fontSize: 16,
fontFamily: 'Inter_400Regular',
fontStyle: 'normal',
fontWeight: '400',
lineHeight: 24,
color: '#4D4D4D',
marginBottom: 30,
},
gradiantStyle: {
width: 248.4,
height: 4.71,
},
});
add the following style to your flatList =>
style={{maxHeight:'what ever you want',flexGrow:0}}

I want to update the parent according to the change of the child to react native

i have a problem updating the parent state. indeed I want to change the edge of an edge after the user has clicked and chosen his level of performance in sport. after having chosen its level of performance, it is then that the selected sport takes a blue border.
please i need help
Sport.js
import React, { useState, useEffect } from "react";
import {
Modal,
Alert,
View,
SafeAreaView,
StyleSheet,
Image,
Text,
TouchableOpacity,
TouchableHighlight,
ScrollView,
} from "react-native";
import AppLoading from "expo-app-loading";
import { useFonts } from "expo-font";
import * as Font from "expo-font";
import { useNavigation } from "#react-navigation/native";
import { ProgressBar, Colors } from "react-native-paper";
import { Ionicons } from "#expo/vector-icons";
import SportItem from "../../Components/SportItem";
import HeadCSearch from "../../Components/HeadCSearch";
import SearchTitle from "../../Components/SearchTitle";
import ModalPicker from "./ModalPicker";
export default function Sport() {
const navigation = useNavigation();
const [chooseData, setchooseData] = useState("0%");
const [sports, setSports] = useState([
{
id: 1,
urlIcon: "ios-football",
name: "Football",
},
{
id: 2,
urlIcon: "hand-left-sharp",
name: "Handball",
},
{
id: 3,
urlIcon: "ios-basketball",
name: "Basketball",
},
{
id: 4,
urlIcon: "ios-car-sport",
name: "Course",
},
{
id: 5,
urlIcon: "ios-baseball",
name: "BaseBall",
},
{
id: 6,
urlIcon: "ios-tennisball",
name: "Tennis",
},
/* {
id: 7,
urlIcon:
"https://img.icons8.com/material-outlined/50/000000/basketball-net.png",
name: "Basketball",
}, */
]);
const [toggle, setToggle] = useState(false);
const [modalOpen, setModalOpen] = useState(false);
const changeModalVisibility = (bool, id) => {
setModalOpen(bool);
sports.map((sport) => {
if (id === sport.id) {
const newState = !toggle;
setToggle(newState);
}
});
};
const setData = (option) => {
setchooseData(option);
};
const OPTIONS = ["Débutant", "Moyen", "Intermédiaire", "Expert"];
let [fontsLoaded] = useFonts({
"Gilroy-ExtraBold": require("../../assets/fonts/Gilroy-ExtraBold.otf"),
"Gilroy-Light": require("../../assets/fonts/Gilroy-Light.otf"),
});
if (!fontsLoaded) {
return <AppLoading />;
} else {
const borderColorValue = toggle ? "#49B5F2" : "white";
return (
<SafeAreaView style={styles.infoCont}>
<ProgressBar
style={{ marginTop: 35, borderRadius: 10 }}
progress={1}
color="#49B5F2"
/>
<View style={styles.containWhite}>
<SearchTitle
styl={styles.whiteText}
partenaire={"Choississez vos Sports Favoris"}
/>
{/* <Modal visible={modalOpen} animationType="slide" transparent={true}>
<View style={{ flex: 1 }}>
<Text>Salut toi</Text>
</View>
</Modal> */}
<Modal
animationType="slide"
transparent={true}
visible={modalOpen}
onRequestClose={() => {
changeModalVisibility(false);
}}
>
<ModalPicker
sports={sports}
OPTIONS={OPTIONS}
setData={setData}
changeModalVisibility={changeModalVisibility}
/>
</Modal>
<ScrollView
contentContainerStyle={{
backgroundColor: "#FFFFFF",
flexWrap: "wrap",
flexDirection: "row",
/* borderColor: "yellow",
borderWidth: 3,
borderStyle: "solid", */
}}
>
{sports.map((sport) => (
<TouchableOpacity
onPress={() => {
changeModalVisibility(true, sport.id);
}}
style={{
alignItems: "center",
display: "flex",
flexDirection: "row",
bottom: 10,
width: 150,
height: 50,
margin: 10,
backgroundColor: "#E4E9DD",
borderColor: borderColorValue,
borderWidth: 1,
borderRadius: 5,
}}
key={sport.id}
>
<View
style={{
alignItems: "center",
display: "flex",
flexDirection: "row",
}}
>
<Ionicons
style={{ left: 8, top: 0 }}
name={sport.urlIcon}
size={20}
color="black"
/>
<Text
style={{
fontFamily: "Gilroy-Light",
fontWeight: "bold",
fontSize: 16,
color: "#000000",
left: 15,
}}
>
{sport.name}
</Text>
</View>
<View style={styles.rate}>
<Text style={styles.rateText}>{chooseData}</Text>
</View>
</TouchableOpacity>
))}
</ScrollView>
</View>
<TouchableOpacity
onPress={() => navigation.navigate("Search")}
style={styles.textinputcont}
>
<Text style={styles.textR}>Continuer</Text>
</TouchableOpacity>
</SafeAreaView>
);
}
}
ModalPicker.js
import React from "react";
import {
View,
Dimensions,
TouchableOpacity,
StyleSheet,
TouchableHighlight,
Text,
} from "react-native";
import { Fontisto } from "#expo/vector-icons";
import SearchTitle from "../../Components/SearchTitle";
export default function ModalPicker(props) {
const WIDTH = Dimensions.get("window").width;
const HEIGHT = Dimensions.get("window").height;
const onPressItem = (option) => {
props.changeModalVisibility(false);
props.setData(option);
};
const option = props.OPTIONS.map((item, index) => {
return (
<TouchableOpacity
style={styles.option}
key={index}
onPress={() => onPressItem(item)}
>
<Text
style={[
styles.textStyle,
{
width: 100,
height: 40,
backgroundColor: "#F7F7F7",
borderRadius: 4,
/* borderColor: "#49B5F2",
borderWidth: 1,
borderStyle: "solid", */
color: "black",
flexDirection: "row",
margin: 2,
top: 5,
flex: 1,
//top: 15,
justifyContent: "center",
alignItems: "center",
},
]}
>
{item}
</Text>
</TouchableOpacity>
);
});
return (
<TouchableOpacity
onPress={() => props.changeModalVisibility(false)}
style={styles.container}
>
<View style={styles.centeredView}>
<View
style={[styles.modalView, { width: WIDTH - 85, height: HEIGHT / 3 }]}
>
<SearchTitle
styl={[styles.whiteText, { top: -50 }]}
partenaire={"Votre Niveau"}
/>
<Text style={[styles.modalText, styles.centeredView, { top: -50 }]}>
{option}
</Text>
<TouchableOpacity
style={{
...styles.openButton,
top: -30,
left: 30,
}}
onPress={() => {
console.log("remove border color");
}}
>
<Text style={styles.textStyle}>Retirez des favoris {" "} </Text>
<Fontisto
style={{ position: "absolute", right: 0, top: 10 }}
name="minus-a"
size={20}
color="black"
/>
</TouchableOpacity>
</View>
</View>
</TouchableOpacity>
);
}
[enter image description here][1]
you need to have the styles dynamically inserted into your code.
and having an event raised from the child component and handled in the parent component, the following code can help to understand that
class Parent extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
backgroundColor: 'yellow'
}
}
onChangeStyle(backgroundColor) {
this.setState({
backgroundColor: backgroundColor
})
}
render() {
return <div style={{backgroundColor: this.state.backgroundColor, padding: 10}}>
<Child onChangeParentStyle={this.onChangeStyle.bind(this)}/>
</div>
}
}
class Child extends React.Component {
onClick() {
this.props.onChangeParentStyle('red');
}
render() {
return <span onClick={this.onClick.bind(this)} style={{background: 'white', cursor: 'pointer'}}>
Change parent style
</span>
}
}
React.render(<Parent />, document.getElementById('container'));
You need to pass from parent to child callback function, and then call it in the child.
const initState = {
show: false
}
const Parent = (props) => {
const [state, setState] = useState({ ...initState })
const updateState = (childState) => {
setState({
show: !state.show
});
}
return (
<Child {...{ updateState }} />
);
}
const Child = (props) => {
const [state, setState] = useState({})
const handleClick = () => {
// You can also pass data to parent
props.updateState(state);
}
return (
<Button onClick={handleClick}>Click Me</Button>
);
}

Undefined is not an object evaluating title.length React Native

When I submit a form in React Native I get the below error undefined is not an object (evaluating 'title.length'). This problem occurs when I submit a form when the Card.js should be rendering the data from the form. I have checked and its getting the data back fine, seems to be a problem with rendering the data that its reading as undefined. After this error the form actually submits successfully and the Card.js displays the data.
Card.js
import React from "react";
import {
StyleSheet,
View,
Text,
ImageBackground,
TouchableOpacity,
} from "react-native";
const Card = (props) => {
const {
navigation,
title,
address,
homeType,
description,
image,
yearBuilt,
price,
id,
} = props;
return (
<TouchableOpacity
onPress={() => props.navigation.navigate("HomeDetail", { houseId: id })}
>
<View style={styles.card}>
<View style={styles.titleContainer}>
<Text style={styles.title}>
{title.length > 30 ? title.slice(0, 30) + "..." : title}
</Text>
</View>
<View style={styles.imageContainer}>
<ImageBackground source={{ uri: image }} style={styles.image}>
<Text style={styles.price}>${price}</Text>
<View style={styles.year}>
<Text style={styles.yearText}>{yearBuilt}</Text>
</View>
</ImageBackground>
</View>
<View style={styles.description}>
<Text style={styles.descriptionText}>
{description.length > 100
? description.slice(0, 100) + "..."
: description}
</Text>
</View>
</View>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
card: {
shadowColor: "black",
shadowOpacity: 0.25,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 8,
borderRadius: 10,
backgroundColor: "#ffffff",
elevation: 5,
height: 300,
margin: 10,
},
titleContainer: {
height: "15%",
padding: 10,
},
title: {
fontSize: 18,
fontWeight: "bold",
color: "gray",
},
imageContainer: {
width: "100%",
height: "65%",
overflow: "hidden",
},
image: {
width: "100%",
height: "100%",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "flex-end",
},
price: {
fontSize: 30,
color: "#fff",
margin: 10,
},
year: {
margin: 10,
backgroundColor: "#2652B0",
height: 25,
width: 80,
borderRadius: 5,
},
yearText: {
fontSize: 20,
color: "#fff",
textAlign: "center",
},
description: {
margin: 10,
},
descriptionText: {
fontSize: 16,
color: "gray",
},
});
export default Card;
HomeListScreen.js
import React, { useEffect, useState } from "react";
import {
StyleSheet,
View,
Text,
FlatList,
ActivityIndicator,
} from "react-native";
import { FloatingAction } from "react-native-floating-action";
import { useDispatch, useSelector } from "react-redux";
import Card from "../components/Card";
import * as houseAction from "../redux/actions/houseAction";
const HomeListScreen = (props) => {
const dispatch = useDispatch();
const [isLoading, setIsLoading] = useState(false);
const { houses } = useSelector((state) => state.house);
useEffect(() => {
setIsLoading(true);
dispatch(houseAction.fetchHouses())
.then(() => setIsLoading(false))
.catch(() => setIsLoading(false));
}, [dispatch]);
if (isLoading) {
return (
<View style={styles.centered}>
<ActivityIndicator size="large" />
</View>
);
}
if (houses.length === 0 && !isLoading) {
return (
<View style={styles.centered}>
<Text>No home found. You could add one!</Text>
</View>
);
}
return (
<View style={styles.container}>
<FlatList
data={houses}
keyExtractor={(item) => item._id}
renderItem={({ item }) => (
<Card
navigation={props.navigation}
title={item.title}
address={item.address}
homeType={item.homeType}
description={item.description}
price={item.price}
image={item.image}
yearBuilt={item.yearBuilt}
id={item._id}
/>
)}
/>
<FloatingAction
position="right"
animated={false}
showBackground={false}
onPressMain={() => props.navigation.navigate("AddHome")}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
centered: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
});
export default HomeListScreen;
<Text style={styles.title}>
{ title ? (title.length > 30 ? title.slice(0, 30) + "..." : title):true}
</Text>
Make sure that title is not undefined.

Is there a way to use mutable arrays in FlatList?

I'm trying to make a toy stopwatch app in order to learn react-native.
I made a lap system, but it is getting way too slow when there are >15 laps. I think the poor performance point is the laps: this.state.laps.concat([d - this.state.lapTimerStart]) part, because of .concat is making a new object every time the Lap button is pressed.
I've heard that .push is way faster than .concat.
So I tried to use .push, but because .push was mutating the array, and FlatList was a PureComponent so it re-rendered only when the props have changed.
I found a way, but it was just the same as doing .concat because basically, it was
let lapArr = this.state.laps;
Array.prototype.push.apply(lapArr, [d - this.state.lapTimerStart]);
this.setState({
laps: lapArr,
})
The full code is
import React, {Component} from 'react';
import {
View,
Text,
StyleSheet,
TouchableHighlight,
FlatList,
} from 'react-native';
import {useTheme} from 'react-native-paper';
import TimeFormatter from 'minutes-seconds-milliseconds';
class Stopwatch extends Component {
constructor(props) {
super(props);
this.state = {
laps: [],
isRunning: false,
mainTimer: null,
lapTimer: null,
mainTimerStart: null,
lapTimerStart: null,
};
}
handleLapReset() {
let {isRunning, mainTimerStart, lapTimer} = this.state;
if (mainTimerStart) {
if (isRunning) {
const d = new Date();
this.setState({
lapTimerStart: d,
lapTimer: d - this.state.lapTimerStart + lapTimer,
laps: this.state.laps.concat([d - this.state.lapTimerStart]),
});
return;
}
this.state.laps = [];
this.setState({
mainTimerStart: null,
lapTimerStart: null,
mainTimer: 0,
lapTimer: 0,
});
}
}
handleStartStop() {
let {isRunning, mainTimer, lapTimer} = this.state;
if (isRunning) {
clearInterval(this.interval);
this.setState({
isRunning: false,
});
return;
}
const d = new Date();
this.setState({
mainTimerStart: d,
lapTimerStart: d,
isRunning: true,
});
this.interval = setInterval(() => {
const t = new Date();
this.setState({
mainTimer: t - this.state.mainTimerStart + mainTimer,
lapTimer: t - this.state.lapTimerStart + lapTimer,
});
}, 10);
}
_renderTimers() {
const {theme} = this.props;
return (
<View
style={[
styles.timerWrapper,
{backgroundColor: theme.colors.background},
]}>
<View style={styles.timerWrapperInner}>
<Text style={[styles.lapTimer, {color: theme.colors.text}]}>
{TimeFormatter(this.state.lapTimer)}
</Text>
<Text style={[styles.mainTimer, {color: theme.colors.text}]}>
{TimeFormatter(this.state.mainTimer)}
</Text>
</View>
</View>
);
}
_renderButtons() {
const {theme} = this.props;
return (
<View style={styles.buttonWrapper}>
<TouchableHighlight
underlayColor={theme.colors.disabled}
onPress={this.handleLapReset.bind(this)}
style={[styles.button, {backgroundColor: theme.colors.background}]}>
<Text style={[styles.lapResetBtn, {color: theme.colors.text}]}>
{this.state.mainTimerStart && !this.state.isRunning
? 'Reset'
: 'Lap'}
</Text>
</TouchableHighlight>
<TouchableHighlight
underlayColor={theme.colors.disabled}
onPress={this.handleStartStop.bind(this)}
style={[styles.button, {backgroundColor: theme.colors.background}]}>
<Text
style={[styles.startBtn, this.state.isRunning && styles.stopBtn]}>
{this.state.isRunning ? 'Stop' : 'Start'}
</Text>
</TouchableHighlight>
</View>
);
}
_renderLaps() {
return (
<View style={styles.lapsWrapper}>
<FlatList
data={this.state.laps}
renderItem={this.renderItem}
keyExtractor={this.keyExtractor}
/>
</View>
);
}
keyExtractor(item, index) {
return index.toString();
}
renderItem({item, index}) {
return (
<View style={styles.lapRow}>
<View style={styles.lapStyle}>
<View style={styles.lapBoxStyle} />
<Text style={styles.lapNumber}>{index + 1}</Text>
</View>
<View style={styles.lapStyle}>
<Text style={styles.lapTime}>{TimeFormatter(item)}</Text>
</View>
</View>
);
}
render() {
return (
<View style={styles.container}>
<View style={styles.top}>{this._renderTimers()}</View>
<View style={styles.middle}>{this._renderButtons()}</View>
<View style={styles.bottom}>{this._renderLaps()}</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {flex: 1},
timerWrapper: {
justifyContent: 'center',
flex: 1,
},
top: {
flex: 1,
},
middle: {
flex: 1,
backgroundColor: '#F0EFF5',
},
bottom: {
flex: 2,
},
mainTimer: {
fontSize: 50,
fontFamily: 'CircularStd-Medium',
alignSelf: 'center',
},
lapTimer: {
fontSize: 18,
fontFamily: 'CircularStd-Medium',
alignSelf: 'flex-end',
},
timerWrapperInner: {
alignSelf: 'center',
},
buttonWrapper: {
flexDirection: 'row',
justifyContent: 'space-around',
paddingTop: 15,
paddingBottom: 30,
},
button: {
height: 80,
width: 80,
borderRadius: 40,
backgroundColor: '#FFF',
justifyContent: 'center',
alignItems: 'center',
},
lapRow: {
flexDirection: 'row',
justifyContent: 'space-between',
height: 40,
paddingTop: 10,
},
lapNumber: {
flexDirection: 'row',
fontSize: 16,
fontFamily: 'CircularStd-Book',
color: '#777',
flex: 1,
},
lapTime: {
flexDirection: 'row',
color: '#000',
fontSize: 20,
fontFamily: 'CircularStd-Book',
flex: 1,
},
startBtn: {
color: '#0C0',
fontFamily: 'CircularStd-Book',
},
stopBtn: {
color: '#C00',
fontFamily: 'CircularStd-Book',
},
lapsWrapper: {
backgroundColor: '#ddd',
},
lapResetBtn: {
fontFamily: 'CircularStd-Book',
},
lapStyle: {
width: '40%',
flexDirection: 'row',
},
lapBoxStyle: {
flexDirection: 'row',
flex: 1,
},
});
export default function StopwatchScreen(props) {
const theme = useTheme();
return <Stopwatch {...props} theme={theme} />;
}
I tried not to use arrow functions, many news, but it didn't help that much.
FlatList is a pure component and it is mandatory to give new ref of data prop to render list . You should use concat but it created new object.
i think the main issue is renderItem.
create a separate PureComponent to avoid re-rendeing of items
class Item extends PureComponent {
const {item,index} = this.props;
return (
<View style={styles.lapRow}>
<View style={styles.lapStyle}>
<View style={styles.lapBoxStyle} />
<Text style={styles.lapNumber}>{index + 1}</Text>
</View>
<View style={styles.lapStyle}>
<Text style={styles.lapTime}>{TimeFormatter(item)}</Text>
</View>
</View>
);
}
and use in render item
renderItem({item, index}) {
return (
<Item item={item} index={index} />
);
}

React Native Component Exception <Text strings must be rendered within a Text component>

I am trying to build a react native application with the expo, First I try to build this application with my chrome web browser, it was worked without any issue after that I try to test the application with my android device and I'm getting an exception - "Text strings must be rendered within a <Text> component" HomeScreen.js files. I have no idea why this happened. My code as follows,
/*This is an Example of Grid View in React Native*/
// import * as React from "react";
import React from 'react';
import { Image, FlatList, StyleSheet, View, Text, TouchableOpacity, TextInput } from 'react-native';
import { COLORS } from '../../asserts/Colors/Colors';
import { CATEGORIES } from '../../asserts/mocks/itemListData';
import CategoryGridTitle from '../components/HomeGridTile';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import { HeaderButton } from '../components/HeaderButton';
import HomeScreenButton from '../components/HomeScreenButton';
//import all the components we will need
const renderTopBarItems = (topBarItems) => {
return (
<TouchableOpacity
style={styles.topBar}>
<Text style={styles.textStyle}> {topBarItems.item.category} </Text>
</TouchableOpacity>
)
}
const HomeScreen = props => {
const renderGridItem = (itemData) => {
return <CategoryGridTitle
title={itemData.item.title}
image={itemData.item.image}
onSelect={() => {
props.navigation.navigate({
routeName: 'PaymentHandlerScreen',
params: {
categoryId: itemData.item.id
}
});
}} />;
}
// const [images, setImages] = React.useState(picsumImages);
return (
<View style={styles.mainBody}>
<View style={styles.searchContainer}>
<TextInput
placeholder='Search'
style={styles.formField}
placeholderTextColor={'#888888'}
/>
<TouchableOpacity onPress={() => props.navigation.navigate('BarCodeScannerScreen')}
style={styles.saveFormField}>
<Image
source={require('../../../images/barcode.png')}
style={{
width: '100%',
height: '30%',
resizeMode: 'contain',
alignContent: 'center',
}}
/> </TouchableOpacity>
</View>
<View style={styles.tabBar}>
<FlatList
horizontal
pagingEnabled={true}
showsHorizontalScrollIndicator={false}
keyExtractor={(item, index) => item.id}
data={CATEGORIES}
renderItem={renderTopBarItems} />
</View>
<FlatList
keyExtractor={(item, index) => item.id}
data={CATEGORIES}
renderItem={renderGridItem}
numColumns={3} />
<HomeScreenButton style={styles.buttonView} />
</View>
);
};
HomeScreen.navigationOptions = navigationData => {
return {
headerTitle: 'Tickets',
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title='profile'
iconName='ios-star'
onPress={() => {
console.log('profile clicked');
}} />
<Item
title='more'
iconName='md-more'
onPress={() => {
console.log('more clicked');
}} />
</HeaderButtons>
)
};
};
export default HomeScreen;
const styles = StyleSheet.create({
mainBody: {
flex: 1,
justifyContent: 'center',
backgroundColor: COLORS.background,
paddingTop: '3%',
},
searchContainer: {
flex: 1,
flexDirection: 'row',
},
tabBar: {
paddingBottom: '3%',
},
topBar: {
width: 150,
borderWidth: 1,
borderRadius: 20,
borderColor: COLORS.primary_blue,
padding: '5%',
marginLeft: '5%',
},
textStyle: {
color: COLORS.primary_blue,
textAlign: 'center',
fontWeight: 'bold',
fontSize: 14,
},
formField: {
flex: 4,
borderWidth: 1,
padding: '4%',
marginLeft: '2%',
borderRadius: 10,
borderColor: COLORS.gray,
backgroundColor: COLORS.gray,
fontSize: 15,
height: '35%',
},
saveFormField: {
flex: 0.5,
justifyContent: 'space-between',
alignItems: 'center',
margin: 10,
},
buttonView: {
position: 'absolute',
bottom: 0,
left: 0,
},
});
Thank you.
I ran into this error a couple of times. RN doesn't like extra spaces in tags. try removing the spaces before and after {topBarItems.item.category}
<Text style={styles.textStyle}>{topBarItems.item.category}</Text>

Categories