Set background color dynamically in React native - reactjs

I´m creating a weather application where I want the background color to change dynamically based on weather conditions fetched from OpenWeatherMaps API. However, I´m not really sure how to do this since I get an error message that says: "Undefined is not an object (near '...}]color...')
Right now I´ve pre-defined the conditions in a separate file called WeatherConditions, and I want the props in my Weather file to determine the background color. How can I do this?
This is my render method in the Weather file. The problem lies in the first view tag after return:
render() {
const {
weatherCondition,
city,
country,
temperature,
placeholder,
weatherDescription,
getWeather,
handleTextChange,
searchedCity
} = this.props;
const {
weatherContainer,
headerContainer,
tempText,
tempContainer,
bodyContainer,
inputContainer,
textInputStyle,
subtitle,
title
} = styles;
return (
<View
style={[
weatherContainer,
{
backgroundColor:
weatherConditions[{ weatherCondition }].color
}
]}
>
{" "}
// Does not work right now.
<View style={headerContainer}>
<Text style={tempText}>
{" "}
{city} {country}
</Text>
<Text style={tempContainer}>
{" "}
{Math.round(temperature)}
˚C
</Text>
</View>
<View style={bodyContainer}>
<View style={inputContainer}>
<TextInput
style={textInputStyle}
onChangeText={searchedCity =>
handleTextChange(searchedCity)
}
onSubmitEditing={() => getWeather()}
placeholder={placeholder}
clearTextOnFocus={true}
enablesReturnKeyAutomatically={true}
/>
</View>
<Text style={title}>{weatherCondition}</Text>
<Text style={subtitle}>{weatherDescription}</Text>
</View>
{this.renderLoading()}
</View>
);
}
My WeatherCondition file:
export const weatherConditions = {
Thunderstorm: {
color: '#303952'
},
Drizzle: {
color: '#8aacb8'
},
Rain: {
color: '#786fa6'
},
Snow: {
color: '#00d8d6'
},
Atmosphere: {
color: '#ff5252'
},
Clear: {
color: '#f5cd79'
},
Clouds: {
color: '#0be881'
},
}

It should be
<View style={[weatherContainer, {
backgroundColor: weatherConditions[weatherCondition].color
}]}>
Note the syntax weatherConditions[weatherCondition].color, you don't need any curly brackets.
weatherConditions is an object, weatherCondition is variable. To access property by variable name, you use bracket notation.

Related

error in passing data through navigation in react native

I'm new to react native world and I'm trying to integrate a calendar with a time slot picker, so I'm trying to pass the selected date from the calendar to the slot picker page but I'm having this Error when I press on a date in the calendar and I couldn't fix it.
TypeError: undefined is not an object (evaluating 'navigation.navigate')
This is my calendar function:
const RequestMeeting = ({ navigation }) => {
const [isModalVisible, setModalVisible] = useState(false);
const toggleModal = () => {
setModalVisible(!isModalVisible);
};
return (
<View style={{ margin: 100, }}>
<Button title="Show modal" onPress={toggleModal} />
<Modal isVisible={isModalVisible} avoidKeyboard={true} scrollHorizontal={true} propagateSwipe={true}>
<ScrollView>
<View style={{ margin: 50, backgroundColor: 'gray', borderRadius: 20, padding: 20, margin: 20 }}>
<Text style={styles.heading}>Request to Buy/Rent</Text>
<View style={{ paddingBottom: 10 }}></View>
<View >
<Calendar
onDayPress={(day) => navigation.navigate("Slot", { bookingDate: day })}
style={styles.calendar}
hideExtraDays
theme={{
selectedDayBackgroundColor: 'green',
todayTextColor: 'green',
arrowColor: 'green',
}}
/>
</View>
<Button
buttonStyle={styles.register}
title="Send Buy/Rent request"
/>
<Button
buttonStyle={styles.cancelbtn}
title="Cancel"
onPress={toggleModal}
/>
</View>
</ScrollView>
</Modal>
</View>
);
};
And this is my time slot picker function:
const jsonData = {
"slots": {
"slot1": "9:00am to 9:30am",
"slot2": "9:30am to 10:00am",
"slot3": "10:00am to 10:30am",
"slot4": "10:30am to 11:00am",
"slot5": "11:00am to 11:30am",
"slot6": "11:30am to 12:00pm"
}
}
const Slot = ({ navigation }) => {
const onPressBack = () => {
const { goBack } = navigation
goBack()
}
const slots = jsonData.slots
const slotsarr = Object.keys(slots).map(function (k) {
return (
<View key={k} style={{ margin: 5 }}>
<TouchableOpacity >
<Text>{slots[k]}</Text>
</TouchableOpacity>
</View>)
});
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" />
<View >
<TouchableOpacity onPress={() => onPressBack()}><Text >Back</Text></TouchableOpacity>
<Text ></Text>
<Text ></Text>
</View>
{ slotsarr}
</View>
);
}
This error means that wherever you are rendering RequestMeeting or Slot (whichever one has the error) it's not getting the navigation prop. If it is rendered as a Screen then it will get the prop from the Navigator. If it's not a top-level screen then you need to pass down the prop from a parent or access it with the useNavigation hook.
Docs: Access the navigation prop from any component

React Native: Keyboard keeps closing on key press when typing in TextInput

I have a functional component Login Screen and have 4 Input Fields in them, along with a login button.
Here is the Full Code for my component Screen:
export default function Login() {
//Configs
const navigation = useNavigation();
const orientation = useDeviceOrientation();
const { colors, dark } = useTheme();
const InputTheme = {
colors: {
placeholder: colors.accent,
primary: colors.accent,
error: "red",
},
};
/** State Codes */
//States
const [login, setLogin] = useState({
email: "",
password: "",
licenseKey: "",
deviceName: "",
});
const [loading, setLoading] = useState(false);
const [secureEntry, setSecureEntry] = useState(true);
//Errors
const [errorEmail, setEmailError] = useState(false);
const [errorPWD, setPWDError] = useState(false);
const [errorLicense, setLicenseError] = useState(false);
const [errorDevice, setDeviceError] = useState(false);
//Error Messages
const [messageEmail, setEmailMessage] = useState("Looks Good");
const [messagePWD, setPWDMessage] = useState("All Good");
async function VerifyInputs() {
var pattern = /^[a-zA-Z0-9\-_]+(\.[a-zA-Z0-9\-_]+)*#[a-z0-9]+(\-[a-z0-9]+)*(\.[a-z0-9]+(\-[a-z0-9]+)*)*\.[a-z]{2,4}$/;
if (login.email == "") {
//Email cannot be empty
setEmailMessage("Email cannot be Blank!");
setEmailError(true);
return;
} else if (login.email != "" && !pattern.test(login.email)) {
//Email is not valid
setEmailMessage("This is not a valid email address!");
setEmailError(true);
return;
} else {
console.log("resolved email");
setEmailMessage("");
setEmailError(false);
}
if (login.password == "") {
//Password cannot be empty
setPWDMessage("Password cannot be Empty!");
setPWDError(true);
return;
} else if (login.password.length < 5) {
//Password must be minimum 5 characters.
setPWDMessage("Password must be of minimum 5 characters!");
setPWDError(true);
return;
} else {
console.log("resolved password");
setPWDMessage("");
setPWDError(false);
}
if (login.licenseKey == "") {
//License Key can't be Empty
setLicenseError(true);
return;
} else {
console.log("License resolved");
setLicenseError(false);
}
if (login.deviceName == "") {
//Device Name can't be empty as well
setDeviceError(true);
return;
} else {
console.log("Device name resolved");
setDeviceError(false);
}
Toast.show("Validation Successful");
}
function MobileContent() {
console.log("mobile_content rerendered");
return (
<View style={{ flex: 1, backgroundColor: colors.accent }}>
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}></View>
<View style={{ flex: 3, justifyContent: "center" }}>
{/**Main Content */}
<View style={[styles.content, { backgroundColor: colors.primary }]}>
<View style={{ flex: 1 }}>
{/**For Header */}
<Header />
</View>
<View style={{ flex: 5 }}>
{/**For Content */}
<ScrollView style={{ flex: 1 }}>
<LoginContent />
</ScrollView>
</View>
<View style={{ flex: 1 }}>
{/**For Footer */}
<Footer />
</View>
</View>
</View>
</View>
);
}
function TabContent() {
console.log("tab_content rerendered");
return (
<View
style={{
flex: 1,
backgroundColor: colors.accent,
flexDirection: orientation.landscape ? "row" : "column",
}}>
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}></View>
<View style={{ flex: 1.5, justifyContent: "center" }}>
{/**Main Content */}
<View style={[styles.content, { backgroundColor: colors.primary }]}>
{/**Header Wrapper */}
<View style={{ justifyContent: "center" }}>
{/**Header Title */}
<Header />
</View>
{/**Content Wrapper */}
<LoginContent />
{/**Footer Wrapper */}
<View style={{ justifyContent: "center" }}>
{/** Login Button */}
<Footer />
</View>
</View>
</View>
</View>
);
}
function Header() {
console.log("header_component rerendered");
return (
<View style={{ margin: "5%" }}>
<Title>Welcome User</Title>
<Subheading>Please Sign In to Continue..</Subheading>
</View>
);
}
function Footer() {
console.log("footer_component rerendered");
return (
<View style={{ margin: isTablet ? "5%" : "3.5%" }}>
<Button
title="Login"
loading={false}
ViewComponent={LinearGradient}
containerStyle={{ maxWidth: isTablet ? "45%" : "100%" }}
buttonStyle={{ height: 50, borderRadius: 10 }}
linearGradientProps={{
colors: [colors.accent, colors.accentLight],
start: { x: 1, y: 1 },
end: { x: 1, y: 0 },
}}
onPress={() => {
VerifyInputs();
//navigation.navigate("verify");
}}
/>
</View>
);
}
function LoginContent() {
console.log("login_component rerendered");
return (
<View style={{ margin: "3%" }}>
{/**Login & Email Wrapper */}
<View style={{ flexDirection: isTablet ? "row" : "column" }}>
<View style={styles.input}>
<TextInput
mode="outlined"
label="Email"
value={login.email}
error={errorEmail}
theme={InputTheme}
onChangeText={(text) => setLogin({ ...login, email: text })}
/>
{errorEmail ? (
<HelperText visible={true} type="error" theme={{ colors: { error: "red" } }}>
{messageEmail}
</HelperText>
) : null}
</View>
<View style={styles.input}>
<View style={{ flexDirection: "row", alignItems: "center" }}>
<TextInput
mode="outlined"
label="Password"
value={login.password}
error={errorPWD}
theme={InputTheme}
secureTextEntry={secureEntry}
style={{ flex: 1, marginBottom: 5, marginEnd: isTablet ? 15 : 5 }}
onChangeText={(text) => setLogin({ ...login, password: text })}
/>
<Button
icon={
<Icon
name={secureEntry ? "eye-off-outline" : "eye-outline"}
size={30}
color={colors.primary}
/>
}
buttonStyle={{
width: 55,
aspectRatio: 1,
backgroundColor: colors.accent,
borderRadius: 10,
}}
containerStyle={{ marginStart: 5 }}
onPress={async () => setSecureEntry(!secureEntry)}
/>
</View>
{errorPWD ? (
<HelperText visible={true} type="error" theme={{ colors: { error: "red" } }}>
{messagePWD}
</HelperText>
) : null}
</View>
</View>
{/**License & Device Wrapper */}
<View style={{ flexDirection: isTablet ? "row" : "column" }}>
<View style={styles.input}>
<TextInput
mode="outlined"
label="License Key"
value={login.licenseKey}
error={errorLicense}
theme={InputTheme}
onChangeText={(text) => setLogin({ ...login, licenseKey: text })}
/>
{errorLicense ? (
<HelperText visible={true} type="error" theme={{ colors: { error: "red" } }}>
License Key cannot be Empty!
</HelperText>
) : null}
</View>
<View style={styles.input}>
<TextInput
mode="outlined"
label="Device Name"
value={login.deviceName}
error={errorDevice}
theme={InputTheme}
onChangeText={(text) => setLogin({ ...login, deviceName: text })}
/>
{errorDevice ? (
<HelperText visible={true} type="error" theme={{ colors: { error: "red" } }}>
Device Name cannot be empty
</HelperText>
) : null}
</View>
</View>
</View>
);
}
return (
<SafeAreaView style={styles.container}>
<StatusBar barStyle={"dark-content"} backgroundColor={colors.accent} />
{isTablet ? <TabContent /> : <MobileContent />}
</SafeAreaView>
);
}
As you can see by looking at the code.. my Login component's rendering responsive component layouts based on device type being phone or tablet, the following components MobileContent or TabContent.
MobileContent functional component wraps my main content in a ScrollView & TabContent functional component doesn't need a scrollview but has responsive scaling views.
Both of these parent components display my common components, Header,LoginContent & Footer.
My Header component just displays a standard title & subheading. My LoginContent component has all the TextInput fields in them with validation logic setup as well. My Footer component has the Submit/Login button. That's All.
So we can summarize the components tree for screen as:
Login Screen/Parent Component => Mobile Content/Tab Content => Header, LoginContent & Footer (Common Components)
Alright, so now what is the issue? the major issue for me lies for TextInputs in LoginContent component, but I assume the underlying issue is applicable for entire Login Screen component.
The ISSUE: When I click on TextInput fields, the input gets focus and Keyboard appears. Everything is fine till this point. As soon as I type even a single letter, single key press on keyboard.. The Keyboard closes immediately and the text input is lost focus.
Why it could be happening? I believe this might be the classic 'React Component Re-render' problem, which causes by TextInput to be re-rendered when state is updated by the onChangeText for the TextInput and hence it loses focus & that's why the Keyboard closes.
So, I hope to resolve atleast first issue from these two issues.
Issue 1: How do I prevent the Keyboard from constantly closing when I try to type something in any of the TextInput fields.
Issue 2: How can I better optimize my Parent & Children components rendering on every state update using the any of these two React Hooks useCallback() and useMemo()?
I've read the documentation for these two hooks useCallback & useMemo multiple times and still haven't grasped the concept of these hooks. All posted examples deal with a Counter Exmaple optimized using useCallback or useMemo but I'm not working with Counters here in my Screen.
I need a more practical exmaple of useCallback() & useMemo() in screen components. Perhaps an implementation of these two hooks in my current Login Screen component will help me understand & grasp the concept better.
Like I mentioned, solving Issue 1 is my highest priority atm, but I know a solution for Issue 2 will help me in the long run as well. It will be very helpful if you can resolve both of my issues here. Thanks for helping.

react native custom picker set style not working

I developing a react native project.
I use react-native-custom-picker but when I try gives a Custom Picker style it's not working. my code like this below
//.. in CustomPicker.js
<CustomPicker
placeholder={labelDefault}
options={options}
getLabel={item => item.label}
optionTemplate={this.renderOption}
selectedValue={this.props.selectedValue}
onValueChange={this.onValueChangeCustomPicker}
textStyle={{color:colors.dark_black,fontSize:25}}--> Here is not work
/>
renderOption() function like this
renderOption(settings) {
const { item, getLabel } = settings
return (
<View style={styles.optionContainer}>
<View style={styles.innerContainer}>
<Text style={{ color: colors.dark_black, alignSelf: 'flex-start', fontSize: 24 }} key={item.key}>{item.label}</Text>
</View>
</View>
)
}
I know Picker style only support IOS.
What's my fault? Any idea!
can you try this code?
I don't know how you organized "options," but you can't work because you don't have any place to take the factors for "colors."
renderOptions:
const options = [
...
color: "black",
]
...
renderOption(settings) {
const { item, getLabel } = settings
return (
<View style={styles.optionContainer}>
<View style={styles.innerContainer}>
<Text style={{ color: item.color, alignSelf: 'flex-start', fontSize: 25 }} key={item.key}>{item.label}</Text>
</View>
</View>
)
}
<CustomPicker
placeholder={labelDefault}
options={options}
getLabel={item => item.label}
optionTemplate={this.renderOption}
selectedValue={this.props.selectedValue}
onValueChange={this.onValueChangeCustomPicker}
/>
I checked source code and documentation if I wanna give style placeholder I should use props for field template like this.
<CustomPicker
fieldTemplateProps={{textStyle:{color:"red",fontSize:22}}}
placeholder={'Please select your favorite item...'}
options={options}
getLabel={item => item.label}
optionTemplate={this.renderOption}
headerTemplate={this.renderHeader}
onValueChange={value => {
Alert.alert('Selected Item', value ? JSON.stringify(value) : 'No item were selected!')
}}
/>
it's worked in my project
more detail

TypeError: Can't read property 'map of undefined in React Native

I am doing react native project. I have array of data and in render method I am trying to looping it, Its like some custom tabbar. But, After loaded, I am trying to switching from one tab to another tab, Its throwing error and crashing like
TypeError: Can't read property 'map of undefined in React Native .
My code is
dashboard.js
constructor(props) {
super(props);
this.state = {
selectedIndex:0,
tabList:[
{tabName: ‘Telugu’, tabActiveImage:TeluguActiveImg, tabInactiveImage: TeluguInActiveImg, tabActiveText:'black', tabInactiveText: 'gray'},
{tabName: ‘Tamil’, tabActiveImage:TeluguActiveImg, tabInactiveImage: TeluguActiveImg, tabActiveText:'black', tabInactiveText: 'gray'},
{tabName: ’Hindi’, tabActiveImage: HindiActiveImg, tabInactiveImage: HindiInActiveImg, tabActiveText:'black', tabInactiveText: 'gray'},
{tabName: ‘English’, tabActiveImage: EnglishActiveImg, tabInactiveImage: EnglishInActiveImg, tabActiveText:'black', tabInactiveText: 'gray'},
]
}
}
OnTabItemHandler = (index) => {
this.setState({selectedIndex:index})
console.log('selected index is',index)
}
render(item) {
const {tabList} = this.state;
return (
<View>Some static data loading </View>
<View style = {styles.tabContainer}>
{
//loop throught the state
this.state.tabList.map((item,index)=>{
return(
//the style just to make it beautiful and easy to debug
<View style ={styles.tabInnerContainer}>
<TouchableOpacity style={styles.tabIcons}
//this onpress to handle of active selected tab
onPress={()=>this.OnTabItemHandler(index)}
>
<Image
//here's the magic show off
source={this.state.selectedIndex=index?item.tabActiveImage:item.tabInactiveImage}
style={styles.tabItemsImages}
/>
<Text style={styles.tabItemTextBlackColor}>{item.tabName}</Text>
</TouchableOpacity>
</View>
)
})
}
</View>
{this.renderBottomContent(item)}
</View>
);
}
}
and bottom view is
based on tab, I am changing the bottom view
renderBottomContent = (item) => {
this.state = { dataArray: getListData()}
switch(selectedTab) {
case "Telugu":
return <View style = {styles.flatListContainer}>
//show flat list data
}
ItemSeparatorComponent = {() => (
<View style={{height:15, backgroundColor:'blue'}/>
)}
/>
</View >
case "Tamil":
return <View style = {styles.bottomStaicScreensForTabs}>
<Text>
Tamil feature will come
</Text>
</View>
case "Hindi":
return <View style = {styles.bottomStaicScreensForTabs}>
<Text>
Hindi feature will come
</Text>
</View>
default:
return <View><Text></Text></View>
}
}
And also tab text colour not changing, always coming as black. Can
anyone help me, where I am doing wrong.
To better understand the problem I've created a snack. I'll post the code here in case it will no longer be available.
Note: it's not styled properly and images are not dynamic as you intend, but it can reproduce the question pretty well.
constructor(props) {
super(props);
this.state = {
selectedIndex: 0,
tabList: [
{
tabName: 'Telugu',
tabActiveImage: '',
tabInactiveImage: '',
tabActiveText: 'black',
tabInactiveText: 'gray',
},
{
tabName: 'Tamil',
tabActiveImage: '',
tabInactiveImage: '',
tabActiveText: 'black',
tabInactiveText: 'gray',
},
{
tabName: 'Hindi',
tabActiveImage: '',
tabInactiveImage: '',
tabActiveText: 'black',
tabInactiveText: 'gray',
},
{
tabName: 'English',
tabActiveImage: '',
tabInactiveImage: '',
tabActiveText: 'black',
tabInactiveText: 'gray',
},
],
};
}
onTabItemHandler = index => {
this.setState({ selectedIndex: index });
};
renderBottomContent = () => {
const { selectedIndex, tabList } = this.state;
const itemSelected = tabList[selectedIndex];
switch (itemSelected.tabName) {
case 'Telugu':
return (
<View style={{backgroundColor: 'yellow'}}>
<Text>Telugu feature will come</Text>
</View>
);
case 'Tamil':
return (
<View style={{backgroundColor: 'green'}}>
<Text>Tamil feature will come</Text>
</View>
);
case 'Hindi':
return (
<View style={{backgroundColor: 'cyan'}}>
<Text>Hindi feature will come</Text>
</View>
);
default:
return (
<View>
<Text>No content</Text>
</View>
);
}
};
render() {
const { tabList, selectedIndex } = this.state;
return (
<View style={styles.container}>
<Text>Some static data loading </Text>
<View style={styles.tabContainer}>
{//loop throught the state
tabList.map((item, index) => {
return (
//the style just to make it beautiful and easy to debug
<View style={styles.tabInnerContainer}>
<TouchableOpacity
style={styles.tabIcons}
//this onpress to handle of active selected tab
onPress={() => this.onTabItemHandler(index)}>
<Image
//here's the magic show off
source={
selectedIndex === index
? require('./assets/snack-icon.png')
: undefined
}
style={{ height: 30, width: 30 }}
/>
<Text
style={{
color:
selectedIndex === index
? item.tabActiveText
: item.tabInactiveText,
}}>
{item.tabName}
</Text>
</TouchableOpacity>
</View>
);
})}
</View>
{this.renderBottomContent()}
</View>
);
}
I'm still here for any clarification or improvement.
Update
Adding style like:
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-start',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
tabContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
},
});

React Native move navigator text

Hey In react native I'm using and Everything works well so far but the title and the back button text don't line up. (The login is higher then register) Any ideas how I could set this up?
render() {
const titleConfig = {
title: 'login',
tintColor: "white",
}
return(
<View style={styles.bb}>
<NavigationBar
title={titleConfig}
tintColor="black" />
</View>
)
}
You can pass in a react element to title prop with styling to make it align as per your requirements. For e.g:
render() {
const title = <View style={styles.navTitle}>
<Text style={styles.navTitleText}>Login</Text>
</View>;
return (
<View style={styles.bb}>
<NavigationBar
title={title}
tintColor="black"
/>
</View>
);
}
var styles = StyleSheet.create({
navTitleText: {
color: "white",
fontSize: 19,
marginBottom: 4,
}
});
Here's the complete guide about the API https://github.com/react-native-fellowship/react-native-navbar#api

Resources