FlatList Render issue in react-navigation - react-native

I am trying to render a FlatList in the home screen using react-navigation after refresing this error message appears:
invariant violation: Objects are not valid as a React child (found: object with keys {screenProps, navigation}). If you meant to render a collection of children, use an array instead.
//App.js
import React from 'react';
import Navigator from './src/Routes/appRoutes';
import { View, Text, StyleSheet } from 'react-native';
import TodoApp from './src/todoApp';
import SingleTodo from './src/components/singleTodo';
const App = () => {
return (
<Navigator />
);
}
const styles = StyleSheet.create(
{
container: {
padding: 40
}
}
)
export default App;
//FlatList screen
import React, { useState } from 'react';
import { View, FlatList } from 'react-native';
import Todos from './components/todos';
import uuid from 'uuid';
const TodoApp = () => {
const [todo, setTodo] = useState([
{
id: uuid(),
title: "FFFFFFFFF",
desc: "first description"
},
{
id: uuid(),
title: "Second title",
desc: "Second description"
}
]
)
return (
<View>
<FlatList
data={todo}
renderItem={({ item }) =>
<Todos title={item.title} desc={item.desc} />}
keyExtractor={item => item.id}
/>
</View>
);
}
export default TodoApp;
//Routes
import { createStackNavigator } from 'react-navigation-stack';
import Todos from './../components/todos';
import SingleTodo from './../components/singleTodo';
import { createAppContainer } from 'react-navigation';
import { Settings } from './../settings';
const screens = {
Home: {
screen: Todos
},
SingleTodo: {
screen: SingleTodo
}
}
const StackScreens = createStackNavigator(screens);
export default createAppContainer(StackScreens);
//Todos screen
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import { NavigationNativeContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const Todos = (props) => {
console.log(props);
const { title, desc } = props;
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => props.navigation.navigate('SingleTodoScreen')}>
<View>{props}</View>
<Text style={styles.listText}>{title}</Text>
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
container: {
padding: 15,
color: "#000",
borderWidth: 1,
borderColor: "#eee",
},
listText: {
fontSize: 16
}
});
export default Todos;

You need to remove the following line from the code
<View>{props}</View>
props is an object, and you can not write the include the object in your JSX.
So your functional component will be like this.
const Todos = (props) => {
console.log(props);
const { title, desc } = props;
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => props.navigation.navigate('SingleTodoScreen')}>
<Text style={styles.listText}>{title}</Text>
</TouchableOpacity>
</View>
)
}

Related

Components not rendering on screen react native expo

There are four components on a screen and only three out of four are rendering. <popDown/> is the component that isn't rendering. When I save the specific component's file the components get rendered. Note: I am saving an already fully updated file. It is running with no errors
The Screen
import react from 'react';
import {View,ScrollView} from 'react-native';
import { SafeAreaView, } from 'react-navigation';
import { PrProvider } from '../appFunctions/PrContext';
import PopDown from '../Components/PRForm/popDown';
import RepsWeightTextInput from '../Components/PRForm/RepsWeightTextInput';
import NotesInput from '../Components/PRForm/NotesInput';
import SubmitPr from '../Components/PRForm/SubmitPr';
const PrEnteryScreen = ({}) => {
return(
<View style = {{height:'100%',width:'100%',backgroundColor:'#141212'}}>
<SafeAreaView style = {{alignItems:'center'}}>
{/**
* use context for pr information
*/}
<PrProvider>
<PopDown />
<RepsWeightTextInput/>
<NotesInput/>
<SubmitPr/>
</PrProvider>
</SafeAreaView>
</View>
);
};
export default PrEnteryScreen;
popdown component
import { useContext, useEffect, useState } from "react";
import { TouchableOpacity,StyleSheet,View,LayoutAnimation,UIManager,Platform,useFocusEffect } from "react-native";
import { Children } from "react/cjs/react.production.min";
import SelectExerciseButton, { setIsOpen } from "./SelectExerciseButton";
import SelectExerciseModal from "../../Screens/SelectExerciseModal";
import { EXERCISE_DATA } from "../../Screens/SelectExerciseModal";
import { PrContext, PrProvider } from "../../appFunctions/PrContext";
if (
Platform.OS === "android" &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
const PopDown = () => {
const value = useContext(PrContext)
const [isOpen,setIsOpen] = useState(false)
const [listHeight,setListHeight] = useState(0)
const [textName,setTextName] = useState(value.exercise);//eventually want to change text based on exercise state
const toggleOpen = () => {
setIsOpen(value => !value);
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
setTextName(value.exercise);
console.log(value.exercise);
}
useEffect(() =>{
EXERCISE_DATA.forEach(()=>{
setListHeight(value => value+50)
})
},[isOpen])
return(
<>
<TouchableOpacity
onPress = {toggleOpen}
>
<SelectExerciseButton />
</TouchableOpacity>
<View>
<SelectExerciseModal style = {isOpen ? styles.show: styles.hidden} listHeight = {listHeight} name = {textName}/>
</View>
</>
)
}
const styles = StyleSheet.create({
hidden:{
height:0,
},
show:{ backgroundColor: '#9B9A9A', width: 200 }
});
export default PopDown;
What I tried
I changed the hidden style height to see if it would render the list that is supposed to pop out of the button. The list did render which means the <selectExerciseButton/> is the only thing not rendering in <popDown/>.
const styles = StyleSheet.create({
hidden:{
height:100,
},
show:{ backgroundColor: '#9B9A9A', width: 200 }
});
<TouchableOpacity
onPress = {toggleOpen}
>
{children}
</TouchableOpacity>
<View>
<SelectExerciseModal style = {isOpen ? styles.show: styles.hidden} listHeight = {listHeight} name = {textName}/>
</View>
<PrProvider>
<PopDown>
<SelectExerciseButton/>
</PopDown>
<RepsWeightTextInput/>
<NotesInput/>
<SubmitPr/>
</PrProvider>
SelectExerciseButton
import { useNavigation,useFocusEffect } from "#react-navigation/native";
import { SafeAreaView, StyleSheet, Text, TouchableOpacity, View,LayoutAnimation } from "react-native";
import { useContext, useState,useEffect } from "react";
import { PrContext } from "../../appFunctions/PrContext";
/**
*
* #returns button that navigates to the a modal to select an exercise
*/
if (
Platform.OS === "android" &&
UIManager.setLayoutAnimationEnabledExperimental
) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
const SelectExerciseButton = () => {
const value = useContext(PrContext)
return(
<>
<View style = {styles.background}>
<Text style = {styles.Text}> {value.exercise} </Text>
</View>
</>
);
};
styles = StyleSheet.create({
background:{
backgroundColor: '#9B9A9A',
width: 335,
borderRadius:41,
alignItems:'center',
marginHorizontal:25,
height:200,
justifyContent:'center'
},
Text:{
fontWeight:'bold',
fontSize:40,
color:'white',
alignItems:'center'
}
})
export default SelectExerciseButton;

react native null is not an object modal

Why I get this error ?
TypeError: null is not an object (evaluating 'modalSuccess.open')
code:
import React, { useEffect, useState, useRef } from 'react';
import { StyleSheet, Text, View, TouchableOpacity, Image, ImageBackground } from 'react-native';
import { useNavigation } from '#react-navigation/native';
import { StatusBar } from 'expo-status-bar';
import Toast from 'react-native-toast-message';
import { updateVerified, toastShown } from '../redux/slice/authSlice';
import { useDispatch, useSelector } from 'react-redux';
import { Portal } from 'react-native-portalize';
import { ModalCollectionSuccess } from '../components/modal/successCollection/ModalCollectionSuccess';
const Profile = () => {
const navigation = useNavigation();
const dispatch = useDispatch();
const user = useSelector(state => state.user);
let modalSuccess = useRef(null).current;
const handleNavigateToAuthRegister = isUser => {
navigation.navigate('AuthRegister', {
isUser
});
};
const handleSetToastToFalse = () => {
Toast.hide();
dispatch(toastShown({user}))
};
useEffect(() => {
user.showCollectionSuccess === true && modalSuccess.open();
}, [user.showCollectionSuccess]);
return (
<View style={{flex: 1}}>
<StatusBar color="#fff" />
<Toast style={{position: 'absolute', zIndex: 2}} ref={(ref) => Toast.setRef(ref)} />
<Portal>
<ModalCollectionSuccess ref={el => (modalSuccess = el)} />
</Portal>
</View>
)
};
export default Profile;
....................................................................................................................................................................................................

Icons are not displaying in HeaderButtons in React-native

Icons are not displaying in HeaderButtons. Instead the text given for fallback is displaying only.
Here is my Code for component:
import React from "react";
import { Platform } from "react-native";
import { HeaderButton } from 'react-navigation-header-buttons';
import { Ionicons } from 'react-native-vector-icons';
import Colors from '../constants/Colors';
const CustomHeaderButton = props => {
return (
<HeaderButton
{...props}
IconComponent={Ionicons}
iconSize={23}
color={Platform.OS === "android" ? "white" : Colors.primaryColor}
/>
);
};
export default CustomHeaderButton;
Here is the file in which I imported it:
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import { MEALS } from '../data/dummy-data';
import HeaderButton from '../components/HeaderButton';
const MealDetailScreen = props => {
const mealId = props.navigation.getParam("mealId");
const selectedMeal = MEALS.find(meal => meal.id === mealId);
return (
<View style={styles.screen}>
<Text>{selectedMeal.title}</Text>
<Button title="Go back to Categories!" onPress={() => {
props.navigation.popToTop();
}} />
</View>
);
}
MealDetailScreen.navigationOptions = (navigationData) => {
const mealId = navigationData.navigation.getParam("mealId");
const selectedMeal = MEALS.find(meal => meal.id === mealId);
return {
headerTitle: selectedMeal.title,
headerRight: () => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Favorite"
iconName="star"
onPress={() => {
console.log("Mark as favorite.");
}}
/>
</HeaderButtons>
)
};
};
const styles = StyleSheet.create({
screen: {
flex: 1,
justifyContent: "center",
alignItems: "center",
// backgroundColor: "white"
}
});
export default MealDetailScreen;
It is not giving any error and giving the output in console. But icon for star is not displaying.
add the below code in android/app/build.gradle and re-run the app.
project.ext.vectoricons = [
iconFontNames: [ 'Ionicons.ttf' ] // Name of the font files you want to
copy
]
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
I got the error.
Instead of this:
import { Ionicons } from 'react-native-vector-icons';
I added this:
import Ionicons from 'react-native-vector-icons/Ionicons';
and icon appeared.
Hi there you can fix this issue by navigating to the android/app/build.gradle
and paste this line at the top and re-run the app by react-native run-android
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"

Component for route must be a React component

I'm trying to make an app with React native and Expo. Im trying to make a navigation from my Profiel.js to ChoosePhoto.js. When im opening the app on my android emulator i'm getting the error "The component for route ProfielS must be a React component.
the navigator
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import ProfielScreen from '../screens/Profiel';
import PhotoScreen from '../screens/ChoosePhoto';
const ProfielNavigator = createStackNavigator ({
ProfielS: ProfielScreen,
PhotoS: PhotoScreen
});
export default createAppContainer(ProfielNavigator);
my app.js
import React from 'react';
import { Text, View, StyleSheet, } from 'react-native';
import ProfielNavigator from './navigation/ProfielNavigator';
export default function App() {
return (
<ProfielNavigator />
);
};
my profiel.js
import React from 'react';
import { Text, View, StyleSheet, Button, Fragement } from 'react-native';
export class GebruikerScherm extends React.Component {
componentWillMount() {
this.getData();
}
constructor() {
super();
this.state = {
gebruikerId: 2,
currentPerson: {},
}
}
getData = () => {
return fetch('(my ip adress)/gebruiker/id?gebruikerId=' + this.state.gebruikerId, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({ currentPerson: responseJson });
console.log(this.state.currentPerson);
})
.catch((error) => {
console.error(error);
});
}
render() {
return(
<View style={styles.container}>
<Text> Gebruiker: {this.state.currentPerson.gebruikerID} </Text>
<Text> Gebruiker: {this.state.currentPerson.gebruikerNaam} </Text>
<Text> Gebruiker: {this.state.currentPerson.biografie} </Text>
</View>
);
};
};
export const ProfielScreen = props =>{
return(
<View style={styles.container}>
<Button title="Profielfoto" onPress={() => {
props.navigation.navigate({
routeName: 'PhotoS'
});
}} />
</View>
);
};
const styles = StyleSheet.create({
container: {
marginTop: 200,
width: '100%',
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
}
});
Choosephoto.js
import React from 'react';
import { Text, View, StyleSheet, } from 'react-native';
const ChoosePhotoScreen = props =>{
return(
<View style={styles.container}>
<Button title="Profielfoto" onPress={() => {
props.navigation.navigate({
routeName: 'PhotoS'
});
}} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default ChoosePhotoScreen;
I expect my profiel.js page with a button. With the onpress action i want to go from profiel.js to choosephoto.js but the page wont even load.
You are wrong in the way you bring in objects.
The object you are trying to use is export only. Not export default
your profiel.js
export const ProfielScreen = props =>{
return(
<View style={styles.container}>
<Button title="Profielfoto" onPress={() => {
props.navigation.navigate({
routeName: 'PhotoS'
});
}} />
</View>
);
};
your Choosephoto.js
...
export default ChoosePhotoScreen;
Usage
import { ProfielScreen } from '../screens/Profiel';
import ChoosePhotoScreen as PhotoScreen from '../screens/ChoosePhoto';
...
const ProfielNavigator = createStackNavigator ({
ProfielS: ProfielScreen,
PhotoS: PhotoScreen
});
Example
import React from 'react'
This essentially says "find the default export from the react module and import that as a constant that I want to call React."
import { React } from 'react'
This says "find the export from the react module which is explicitly named React, and import that here as a constant that I want to call React."
in profiel.js add default keyword to export :
export default class GebruikerScherm extends React.Component {...
and also recheck all related paths in imports of screens.

How to call mapStateToProps on each instance of a Component in React-Redux

I have a component called AuditionItem, multiple instances of which are added to the parent component called AuditionsList.
I have done export default connect(mapStateToProps)(AuditionItem)
From my experience mapStateToProps is called only for one instance of AuditionItem (the one that initiates the state change). But I want the mapStateToProps to be called for EACH instance of AuditionItem.
Is there a way to do this?
Here's my code for AuditionItem.js:
import React from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity } from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import Moment from 'moment';
import colors from './../styles/colors';
import { store } from './../App';
import { addBookmark, removeBookmark } from './../actions/creators';
import { connect } from 'react-redux';
class AuditionItem extends React.Component {
_toggleBookmark = (auditionId, bookmarked) => {
if(bookmarked)
store.dispatch(removeBookmark(auditionId));
else
store.dispatch(addBookmark(auditionId));
}
render() {
Moment.locale('en');
let bookmarked = (this.props.auditions.indexOf(this.props.auditionId) > -1) ? true : false;
let roleString = String(this.props.role);
if(roleString.length > 35)
roleString = roleString.substring(0, 35) + " ...";
let projectString = String("Project: (" + this.props.productionType + ") " + this.props.project);
if(projectString.length > 35)
projectString = projectString.substring(0, 35) + " ...";
let productionHouseString = String("Production House: " + this.props.productionHouse);
if(productionHouseString.length > 35)
productionHouseString = productionHouseString.substring(0, 35) + " ...";
let iconName = `ios-bookmark${bookmarked ? '' : '-outline'}`;
return (
<View style={styles.auditionItemWithBookmark}>
<View style={styles.bookmark}>
<TouchableOpacity onPress={() => this._toggleBookmark(this.props.auditionId, bookmarked)} >
<Ionicons name={iconName} size={25} />
</TouchableOpacity>
</View>
<View style={styles.auditionItem}>
<Text style={styles.role}>{roleString}</Text>
<Text style={styles.project}>{projectString}</Text>
<Text style={styles.productionHouse}>{productionHouseString}</Text>
<Text style={styles.auditionDate}>Begins: {Moment(String(this.props.auditionDate).replace('"','').replace('"', '')).format('LLLL')}</Text>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
auditionItemWithBookmark: {
flex: 1,
flexDirection: "row",
backgroundColor: colors.auditionItemBackgroundColor,
borderRadius: 10,
margin: 10,
padding: 15,
},
bookmark: {
flex: 1,
paddingTop: 5,
},
auditionItem: {
flex: 8,
flexDirection: "column",
backgroundColor: colors.auditionItemBackgroundColor,
},
role: { color: colors.auditionItemColor, fontSize: 20, fontWeight: "bold" },
project: { color: colors.auditionItemColor },
productionHouse: { color: colors.auditionItemColor },
auditionDate: { color: colors.auditionItemColor },
});
const mapStateToProps = state => {
return {
auditons: state.bookmarks.auditions,
}
}
export default connect(mapStateToProps)(AuditionItem);
And the code for the parent AuditionsList.js
import React from 'react';
import { Text, View, FlatList, ActivityIndicator } from 'react-native';
import { connect } from 'react-redux';
import AuditionItem from './AuditionItem';
import Auditions from './../data/Auditions';
import { store } from './../App';
class AuditionsList extends React.Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: [] }
}
componentDidMount() {
this._refreshData();
}
componentDidUpdate(prevProps) {
if((this.props.location !== prevProps.location) || (this.props.roleType !== prevProps.roleType))
this._refreshData();
}
_onRefresh() {
this.setState({ isLoading: true }, this._refreshData() );
}
_refreshData = () => {
Auditions.fetchAuditions(this.props.productionType, this.props.location, this.props.roleType).then(auditions => {
this.setState({ isLoading: false, data: this._addKeysToAuditions(auditions) });
});
}
_addKeysToAuditions = auditions => {
return auditions.map(audition => {
return Object.assign(audition, { key: audition.Role});
});
}
_renderItem = ({ item }) => {
return (
<AuditionItem
auditionId={item.objectId}
role={item.Role}
project={item.Project.Name}
productionType={item.Project.ProductionType.Type}
auditionDate={JSON.stringify(item.Date.iso)}
productionHouse={item.Project.ProductionHouse.Name}
auditions={store.getState().bookmarks.auditions}
/>
);
}
render() {
if (this.state.isLoading) {
return (
<View style={{flex: 1, paddingTop: 20}}>
<ActivityIndicator />
</View>
);
}
return (
<View style={{ flex: 1 }}>
<FlatList onRefresh={() => this._onRefresh()} refreshing={this.state.isLoading} data={this.state.data} renderItem={this._renderItem} />
</View>
);
}
}
const mapStateToProps = state => {
return {
location: state.settings.location,
roleType: state.settings.roleType,
};
}
export default connect(mapStateToProps)(AuditionsList);
Code for App.js:
import React from 'react';
import { Text, View, ActivityIndicator } from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import { Header } from 'react-native-elements';
import { createMaterialBottomTabNavigator } from 'react-navigation-material-bottom-tabs';
import { SettingsDividerShort, SettingsCategoryHeader, SettingsPicker} from 'react-native-settings-components';
import BookmarksScreen from './screens/BookmarksScreen';
import AuditionsScreen from './screens/AuditionsScreen';
import SettingsScreen from './screens/SettingsScreen';
import { AsyncStorage } from "react-native";
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import rootReducer from './reducers/index';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/lib/integration/react';
import { autoMergeLevel2 } from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
const persistConfig = {
key: 'root',
storage: AsyncStorage,
stateReconciler: autoMergeLevel2,
whitelist: ['settings', 'bookmarks']
};
const pReducer = persistReducer(persistConfig, rootReducer);
export const store = createStore(pReducer);
export const persistor = persistStore(store);
const MaterialBottomTabNavigator = createMaterialBottomTabNavigator(
{
Bookmarks: BookmarksScreen,
Auditions: AuditionsScreen,
Settings: SettingsScreen,
},
{
shifting: true,
initialRouteName: 'Auditions',
barStyle: { backgroundColor: 'black' },
}
);
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<PersistGate loading={<ActivityIndicator />} persistor={persistor}>
<MaterialBottomTabNavigator />
</PersistGate>
</Provider>
)
}
}
This doesn't create an instance of the class, it just exports the class/object.
export default connect(mapStateToProps)(AuditionItem)
Export reference
You get the instance when you call the constructor of the class, but that's after importing it. So basically, all the time you use the imported AuditionItem (i.e: < AuditionItem />) React internally is creating a new instance of the class.
I guess the problem is either on AuditionItem itself, or the props you're passing to.
Additional information about mapStateToProps
from the official Redux documentation
[mapStateToProps(state, [ownProps]): stateProps] (Function): If this argument is specified, the new component will subscribe to Redux store updates. This means that any time the store is updated, mapStateToProps will be called. The results of mapStateToProps must be a plain object, which will be merged into the component’s props. If you don't want to subscribe to store updates, pass null or undefined in place of mapStateToProps.