react-native-multiselect-view - render containers as "pressed" - react-native

react-native-multiselect-view is a seemingly simple library.....however I cant find a way to render a container as "pressed" (i.e. active) without physically pressing it. I want user to make choices and store them in Firebase.....this way when they re-open the app I will fetch choices from Firebase and update UI for their previous selections. Im guessing I need to change the data array data={['item1', 'item2']} to reflect whether item is active or not.....but cant figure out exactly how
import MultiSelectView from 'react-native-multiselect-view';
<MultiSelectView
data={['item1', 'item2']}
inactiveContainerStyle={{padding:2, borderColor: colorConsts.c3, opacity:0.25, borderWidth: 2, borderRadius:sizeConsts.widgetBorderRadius, backgroundColor:'white'}}
activeContainerStyle={{padding:2, borderColor: colorConsts.c2, borderWidth: 2, borderRadius:sizeConsts.widgetBorderRadius, backgroundColor:'white'}}
activeTextStyle={{color:colorConsts.c2}}
inactiveTextStyle={{color:colorConsts.c3}}
inactiveIcon={<IconFA name="plus-circle" size={20} style={{color:colorConsts.c3}}/>}
activeIcon={<IconFA name="minus-circle" size={20} style={{color:colorConsts.c2}}/>}
onSelectionStatusChange={this._onSelectionStatusChange}
/>

I emailed author who kindly came right back to me with: "It's not implemented at the moment. But here the code screenshot where it can be handled. U can raise a PR or fork repo and do it. If u need me to do it for u let me know.."
I decided instead to write my own and use much of the authors code (below)....I pull user preferences from Firebase....into Redux....into local state
/* eslint-disable react-native/no-inline-styles */
import React, {Component} from 'react';
import {View, TouchableOpacity, Text, StyleSheet} from 'react-native';
import {sizeConsts, colorConsts} from '../globalConst';
import IconFA from 'react-native-vector-icons/FontAwesome';
import database from '#react-native-firebase/database';
import {connect} from 'react-redux';
//*********************************************************
//REDUX
//*********************************************************
const passStateToProps = state => ({
arrObjInterests: state.profile.mySelf.arrInterests,
userId: state.auth.userId,
});
class MyMultiSelectView extends Component {
//To update the status of any arrInterests object, run a map on the array and check for some unique value of each object,
//in case of condition=true, return the new object with updated value, else same object.
_onPress = (label, oldValue) => {
//FIRST UPDATE STATE FOR QUICK UI RESPONSE
this.setState(
prevState => ({
//map through prevState interests array and return each object same as you saw it
//.....unless its a match in which case you update the value
arrInterests: prevState.arrInterests.map(obj =>
obj.label === label ? {...obj, value: !oldValue} : obj,
),
}),
() => {
//NEXT UPDATE FBS WITH UPDATED STATE
//prettier-ignore
database().ref('/profiles/users/' + this.props.userId + '/arrInterests').set(this.state.arrInterests);
},
);
};
constructor(props) {
super(props);
//populate state with interests array arrInterests from Redux arrObjInterests
this.state = {
arrInterests: this.props.arrObjInterests,
};
}
render() {
return (
//prettier-ignore
<View
style={{flexDirection: 'row', flexWrap: 'wrap', flex: 1, padding: 15}}>
{/* map through interests array and create TouchableOpacity for each */}
{this.state.arrInterests.map((item, index) => (
<TouchableOpacity key={index} onPress={() => {
this._onPress(item.label, item.value);
}}>
<View style={!item.value ? [styles.container, {borderColor: colorConsts.c3, opacity:0.25}] : [styles.container, {borderColor: colorConsts.c2}]}>
<Text style={!item.value ? [styles.text, {color:colorConsts.c3}] : [styles.text, {color:colorConsts.c2}]}>{item.label}</Text>
{!item.value ? <IconFA name="plus-circle" size={20} style={[styles.icon, {color:colorConsts.c3}]}/> : <IconFA name="minus-circle" size={20} style={[styles.icon, {color:colorConsts.c2}]}/>}
</View>
</TouchableOpacity>
))}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
paddingVertical: 5,
marginTop: 10,
marginRight: 10,
paddingLeft: 10,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
borderWidth: 2,
borderRadius: sizeConsts.widgetBorderRadius,
backgroundColor: '#f8f8f8',
},
text: {
fontSize: 16,
color: 'black',
marginRight: 6,
},
icon: {
width: 20,
marginRight: 2,
},
});
export default connect(
passStateToProps,
null,
)(MyMultiSelectView);

Related

How can I send different functions from index in order to re use the footer code?

Im new in React, and Im starting with React native.
I'm working in my project, and in order to re-use code, I'm reading about HOC.
My use case is: I have a lot of views with a footer that have some buttons (one or two, it depends. They might have different actions, some of them navigates to another activity, other execute functions or state updates).
Im trying to execute a navigation.navigate from the "main" view, but I got an error: "Cant find variable: navigation".
This is my code:
index.js
import {
Text,
StyleSheet,
View,
TouchableOpacity,
ScrollView
} from 'react-native';
import withFooter from '../../components/withFooter';
const SignUp = ({ navigation }) => {
return (
<View style={styles.container}>
<View style={{ flex: 3 }}>
<Text>Test</Text>
</View>
</View>
)
};
export default withFooter(SignUp, {
buttons: [
{
text: 'Exit',
action: () => console.log('Exit'),
},
{
text: 'Accept',
action: () => navigation.navigate('PersonalDataSignUp'),
}
]
});
withFooter.js
import { Text, View, TouchableOpacity, StyleSheet } from 'react-native';
const withFooter = (WrappedComponent, { buttons }) => {
const WithFooter = props => {
return (
<>
<WrappedComponent {...props} />
<View style={{
flexDirection: 'row',
padding: 20
}}>
{
buttons.map(button => (
<TouchableOpacity style={[styles.button]} onPress={button.action}>
<Text style={{ fontWeight: '900' }}>{button.text}</Text>
</TouchableOpacity>
))
}
</View>
</>
)
};
return WithFooter;
};
const styles = StyleSheet.create({
button: {
flex: 1,
height: 50,
borderRadius: 5,
backgroundColor: '#FCCC00',
justifyContent: 'center',
alignItems: 'center',
borderColor: 'black',
borderWidth: 1
},
})
export default withFooter;
How can I send different functions from index in order to re use the footer code? Is there any other way to do it?. Thanks in advance!

Invariant Violation: View config getter callback for component `div` must be a function (received `undefined`)

i am getting error -
Invariant Violation: View config getter callback for component div must be a function (received undefined). Make sure to start component names with a capital letter.
in below code, can anyone help me to find the bug?
All component are capital and rest are checked too.
import React from "react";
import { Pressable, StyleSheet, Text, TouchableOpacity } from "react-native";
import { FlatList } from "react-native-web";
export default function ListItem(props) {
const onDelete = (goalId) => {
props.setCourseGoal((currGoal) => {
return currGoal.filter((goal) => goal.key !== goalId);
});
};
return (
<FlatList
data={props.courseGoal}
keyExtractor={(item, index) => item.key}
renderItem={(itemData) => (
<TouchableOpacity
activeOpacity={0.2}
style={styles.touchList}
>
<Text style={styles.listData}>{itemData.item.value}</Text>
<Pressable style={styles.closeBtn} title="Click Me !" onPress={onDelete.bind(this, itemData.item.key)}>
<Text>❌</Text>
</Pressable>
</TouchableOpacity>
)}
/>
);
}
const styles = StyleSheet.create({
touchList: {
flexDirection: "row",
marginVertical: 5,
},
listData: {
width: "90%",
textAlign: "center",
padding: 10,
borderRadius: 10,
borderWidth: 1,
marginHorizontal: 5,
},
closeBtn: {
color: "black",
justifyContent: "space-around",
padding: 10,
borderRadius: 10,
borderWidth: 1,
},
});
Found the solution -
its on line 3 ,
import { FlatList } from "react-native-web";
need to import react-native

onPress Handler of a button updates the state but screen goes blank

I am learning react native and trying to build a todo app. In the code below, I have two useState hooks one for keeping track of what user enters and allTodo one for keeping track of all the todos to be rendered, also I'm using FlatList for rendering todos but when I submit the todo, the screen just goes blank and nothing appears again until I refresh it again. Also I'm testing the app on chrome by selecting a device in it. could that be a problem? Please let me know what the problem is. Code is below:
import React, { useState } from "react";
import {
StyleSheet,
Text,
View,
TextInput,
FlatList,
TouchableOpacity,
Button,
} from "react-native";
export default function App() {
const [allTodos, setAllTodos] = useState(["a", "b"]);
const [todo, setTodo] = useState("");
const handleSubmit = () => {
setAllTodos(allTodos.push(todo));
setTodo("");
};
return (
<View style={styles.container}>
<Text>{todo}</Text>
<Text>Todo: </Text>
<TextInput
style={styles.input}
placeholder="E.g. Buy eggs"
onChangeText={(val) => setTodo(val)}
/>
<Button title="Add Todo" onPress={handleSubmit} />
<FlatList
data={allTodos}
// keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<TouchableOpacity>
<Text style={styles.item}>{item}</Text>
</TouchableOpacity>
)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#FBF4E9",
alignItems: "center",
// justifyContent: "center",
paddingTop: 20,
},
item: {
marginTop: 24,
padding: 30,
backgroundColor: "pink",
fontSize: 24,
marginHorizontal: 10,
marginTop: 24,
},
input: {
borderWidth: 1,
borderColor: "#777",
padding: 8,
margin: 10,
width: 200,
},
});
This is what it looks before submitting the todo:
Image after I submit it:
Thank you
Don't mutate state. In your handleSubmit function, you are mutating the state allTodos.
simply change your handleSubmit function to,
const handleSubmit = () => {
const currentTodos = [...allTodos];
currentTodos.push(todo);
setAllTodos(currentTodos);
setTodo('');
};
Also you might want to pass the value prop of TextInput as todo.
Check this Live Snack to see it in action.

fetch API (Error) Getting the same result

I am developing a simple weather app using react-native. Using fetch-api, i am requesting for weather of cities based on thier IDs but even though i am inputting different city IDs, i am getting the same default result . Here is my code :-
This is my main component
import React, {Component} from 'react';
import {StyleSheet, Text, View, TextInput} from 'react-native';
import Forecast from "./Forecast";
import OpenWeatherMap from "./openweather"
export default class Weather extends Component {
state = {
forecast: null
}
handleTextChange = event => {
let zip = event.nativeEvent.text;
OpenWeatherMap.fetchForecast(zip).then(forecast => {
console.log(forecast);
this.setState({forecast: forecast});
});
}
render() {
let content = null;
if(this.state.forecast !== null){
content = (
<Forecast
main = {this.state.forecast.main}
description = {this.state.forecast.description}
temp = {this.state.forecast.temp} />
);
}
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Enter your City ID
</Text>
{content}
<TextInput
style={styles.input}
onSubmitEditing={this.handleTextChange} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#808000',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
input:{
fontSize: 20,
borderWidth: 2,
padding: 2,
height: 40,
width: 100,
textAlign: "center"
}
});
This is my child component used only for display purposes..
Forecast.js
import React, {Component} from 'react';
import {StyleSheet, Text, View} from 'react-native';
class Forecast extends Component {
render(){
return(
<View style={styles.container}>
<Text style={styles.bigText}>
{this.props.main}
</Text>
<Text style= {styles.mainText}>
Current conditions: {this.props.description}
</Text>
<Text style= {styles.bigText}>
{this.props.temp} ^ F
</Text>
</View>
);
}
}
const styles= StyleSheet.create({
container: {height: 130},
bigText:{
flex:2,
fontSize: 20,
textAlign: "center",
margin: 10,
color: "#800000"
},
mainText : {flex:1, fontSize: 16, textAlign: "center", color: "#800000"}
});
export default Forecast;
This is where i use fetch api for requesting weather from openweathermap :-
const weather_api_key = "7e901f7ecb8b36c60ccca4a64c90ee1a";
const weather_url ="https://samples.openweathermap.org/data/2.5/weather?";
function zipurl(zip){
return `${weather_url}id=${zip}&APPID=${weather_api_key}`;
}
function fetchForecast(zip){
return fetch(zipurl(zip))
.then(response => response.json())
.then(responseJSON => {
return {
main:responseJSON.weather[0].main,
description:responseJSON.weather[0].description,
temp:responseJSON.main.temp
};
})
.catch(error=>{
console.error(error);
});
}
export default {fetchForecast: fetchForecast}
My path for different files is :-
You're using the samples.openweathermap.org endpoint, instead of the api.openweathermap.org endpoint. The second one is the one that you want to use, and that actually gives you different data depending on the query parameters.
By the way, thank you for posting the relevant code. It made it much easier to debug your problem. Although in my opinion, you posted much more than needed. I only used the last code snippet as that is where the problem lies. Not in the rendering of the data. Also for next time, consider adding a sample output of the API vs. what you were expecting. And I'd recommend you to change your API key now that you've got your solution.

How to add icon in each tab in custom Tabs?

I am using react-navigation .
I want to add icon for the tab.
CustomTabs.js from example directory
if you are to use react-native-vector-icon is much easier, just create an array like the one i created below, for all the names of the icon you want to use and if you want to use image, then you will have to use image links because the last time i checked react native won't allow you to load static assets dynamically.
Benefit of using an icon especially react-native-vector-icon:
Access to tonnes of iconsets.
Styling based on if its focused or not.
....and others things i can't remember.
`
.....
import Icon from 'react-native-vector-icons/Ionicons';
const styles = {
body: {
backgroundColor: '#3b4147',
height: 60,
},
tabWrapper: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
height: 50,
},
tabInnerWrapper: {
marginRight: 12,
marginLeft: 12,
justifyContent: 'center',
alignItems: 'center',
},
textStyle: {
fontSize: 12,
color: '#62666b',
},
focusTextStyle: {
fontSize: 12,
color: '#acafb1',
},
};
const {body, tabWrapper, tabInnerWrapper, textStyle, focusTextStyle} = styles;
const focusIconColor = '#acafb1';
const iconColor = '#62666b';
const IconNames = ['ios-compass-outline', 'ios-cut-outline', 'ios-chatboxes-outline'];
const IconNamesFocus = ['ios-compass', 'ios-cut', 'ios-chatboxes'];
const CustomTabBar = ({ navigation: { state, navigate }}) => {
const { routes } = state;
return (
<View style={body}>
<View style={tabWrapper}>
{routes && routes.map((route, index) => {
const focused = index === state.index;
return (
<TouchableOpacity
key={route.key}
onPress={() => navigate(route.routeName)}
style={tabInnerWrapper}
>
<Icon
name={focused ? IconNamesFocus[index] : IconNames[index]}
size={25}
color={focused ? focusIconColor : iconColor}
/>
<Text style={focused ? focusTextStyle : textStyle}>
{route.routeName}
</Text>
</TouchableOpacity>
);
})}
</View>
</View>
);
};
`