React Native undefined is not an object (evaluating 'props.navigation.toggleDrawer') - react-native

I'm new to react native and so I'm wondering why I'm receiving an error like
"undefined is not an object (evaluating 'props.navigation.toggleDrawer')" when I try to click on hamburger menu in my Home
Here below my Home.js
const NavigatorHome = props => {
return (
<View>
<AppHeader navigation={props.navigation} title="Home" />
</View>
);
};
export default class Home extends Component {
state = {
users: []
}
async componentDidMount() {
const users = await ajax.fetchUsers();
//ET20200226 This was a warning
this.setState({users});
}
render() {
return (
<View>
<NavigatorHome></NavigatorHome>
<View>
<Text style={styles.h2text}>
List of requests
</Text>
<FlatList
data={this.state.users}
showsVerticalScrollIndicator={false}
renderItem={({item}) =>
<View style={styles.flatview}>
<Text style={styles.uuid}>{item.uuid}</Text>
</View>
}
keyExtractor={item => item.uuid}
/>
</View>
</View>
);
}
}
Here my AppHeader.js
const AppHeader = props => {
return (
<Header
//leftComponent={<HamburgerMenu navigation={props.navigation} />}
leftComponent={<Icon
color="#fff"
name="menu"
onPress={() => props.navigation.toggleDrawer()}
/>}
centerComponent={{
text: props.title,
style: { color: "#fff", fontWeight: "bold" }
}}
statusBarProps={{ barStyle: "light-content" }}
/>
);
};
export default AppHeader;
Can someone help me to figure out how to fix it?

The reason for the error is that props.navigation is undefined in NavigatorHome. you must pass props.navigation to NavigatorHome. Your code should be as follows:
<View>
<NavigatorHome navigation={this.props.navigation}></NavigatorHome>
<View>

Related

I am not able to navigate to the other screen in my react native project the error is: navigation not found

const Item = ({ item }) => (
<TouchableOpacity
onPress={() => this.navigation.navigate(
"carProfile",
{item: item}
)}>
<View style={styles.item}>
<Text style={styles.title}>{item.name}</Text>
<Text style={styles.details}>{item.details}</Text>
</View>
</TouchableOpacity>
);
const List = (props,navigation) => {
const renderItem = ({ item }) => {
if (props.searchPhrase === "") {
return <Item item={item} />;
}
if (item.name.toUpperCase().includes(props.searchPhrase.toUpperCase().trim().replace(/\s/g, ""))) {
return <Item item={item} />;
}
if (item.details.toUpperCase().includes(props.searchPhrase.toUpperCase().trim().replace(/\s/g, ""))) {
return <Item item={item} />;
}
};
return (
<SafeAreaView style={styles.list__container}>
<View
onStartShouldSetResponder={() => {
props.setClicked(false);
}}
>
<FlatList
data={props.data}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</View>
</SafeAreaView>
);
};
export default List;
the error is continuing to be there despite me trying to put navigation container in different positions. I want to send the user to the carProfile page, where the data passed in item is reused. This way user can know about the selection they are looking for
Use this way
onPress={() => this.props.navigation.navigate(
"carProfile",
{item: item}
)}
The navigation is inside the props, not as a second argument. Below is a classic example. And also note, you cannot extract navigation prop for child components, it will only work on Main components(Screens).
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
If you want to use navigation inside child components, you can use the navigation hooks.
import { useNavigation } from "#react-navigation/native";
function MyBackButton() {
const navigation = useNavigation();
return (
<Button
title="Back"
onPress={() => {
navigation.goBack();
}}
/>
);
}

Flatlist doesn't display the list from useContext

In react native app, I have a home screen and a second screen that the user uses to add items that should be displayed on the home screen. I am using context to save the list of items. The problem is when I add items to the second screen and go to the home screen. The displayed list is empty.
Any help to explain why this happens and how to handle it? Here's the
Data Context
export const ExpenseContext = createContext();
App.js
const Stack = createNativeStackNavigator();
function App() {
const [expenseList, setExpenseList] = useState([]);
return (
<NavigationContainer>
<ExpenseContext.Provider value={{ expenseList, setExpenseList }}>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={{ title: "Dashboard" }}
/>
<Stack.Screen
name="AddItem"
component={AddItem}
options={{ title: "CashFlowCreate" }}
/>
</Stack.Navigator>
</ExpenseContext.Provider>
</NavigationContainer>
);
}
export default App;
Home.js
function Home({ route, navigation }) {
const { expenseList } = useContext(ExpenseContext);
return (
<View style={styles.container}>
<Text style={styles.text}>Budget:</Text>
<Button title="+" onPress={() => navigation.navigate("AddItem")} />
<View>
<FlatList
style={styles.listContainer}
data={expenseList}
renderItem={(data) => <Text>{data.item.name}</Text>}
/>
</View>
</View>
);
}
export default Home;
AddItem.js
function AddItem({ navigation }) {
const { expenseList, setExpenseList } = useContext(ExpenseContext);
const [name, setName] = useState("");
const [amount, setAmount] = useState("");
const itemsList = expenseList;
return (
<View style={styles.container}>
<TextInput
style={styles.input}
onChangeText={(name) => setName( name )}
value={name}
placeholder="Name"
keyboardType="default"
/>
{name === "" && (
<Text style={{ color: "red", fontSize: 12, paddingLeft: 12 }}>
Name is required
</Text>
)}
<TextInput
style={styles.input}
onChangeText={(amount) => setAmount( amount )}
value={amount}
placeholder="Amount"
keyboardType="numeric"
/>
{amount === "" && (
<Text style={{ color: "red", fontSize: 12, paddingLeft: 12 }}>
Amount is required
</Text>
)}
<Button
title="Add"
style={styles.btn}
onPress={() => {
if (name === "" || amount === "") {
alert("Please Enter the required values.");
} else {
itemsList.push({
name: name,
amount: amount,
});
setExpenseList(itemsList);
}
}}
/>
<Button
title="View Dashboard"
style={styles.btn}
onPress={() => {
navigation.navigate("Home");
}}
/>
</View>
);
}
export default AddItem;
I solve it, in AddItem component remove const itemsList = expenseList; and onPress add button it should be like that instead
onPress={() => {
name === "" || amount === ""
? alert("Please Enter the required values.")
: setExpenseList([
...expenseList,
{
key:
Date.now().toString(36) +
Math.random().toString(36).substr(2),
name: name,
amount: amount,
},
]);
}}
I added the key because I needed later on.
There are several areas of issues in your code. One issue I can see is in AddItem. When you set:
const itemsList = expenseList
I think you did this for:
itemsList.push({
name: name,
amount: amount,
});
But you should look at the spread operator and try:
setExpenseList(...expenseList, {
name,
amount,
})
rewrite of AddItem.js:
function AddItem({ navigation }) {
const { expenseList, setExpenseList } = useContext(ExpenseContext)
const [name, setName] = useState('')
const [amount, setAmount] = useState('')
return (
<View style={styles.container}>
<TextInput style={styles.input} onChangeText={setName} value={name} placeholder='Name' keyboardType='default' />
{name === '' ? <Text style={styles.err}>Name is required</Text> : null}
<TextInput style={styles.input} onChangeText={setAmount} value={amount} placeholder='Amount' keyboardType='numeric' />
{amount === '' ? <Text style={styles.err}>Amount is required</Text> : null}
<Button
title='Add'
style={styles.btn}
onPress={() => {
name === '' || amount === ''
? alert('Please Enter the required values.')
: setExpenseList(...expenseList, {
name: name,
amount: amount,
})
}}
/>
<Button title='View Dashboard' style={styles.btn} onPress={() => navigation.navigate('Home')} />
</View>
)
}
export default AddItem
In your Home.js your FlatList it's missing the keyExtractor and you're trying to declare a prop of title outside of <Text>, rewrite:
function Home({ navigation }) {
const { expenseList } = useContext(ExpenseContext);
return (
<View style={styles.container}>
<Text style={styles.text}>Budget:</Text>
<Button title="+" onPress={() => navigation.navigate("AddItem")} />
<View>
<FlatList
style={styles.listContainer}
data={expenseList}
keyExtractor={(_,key) => key.toString()}
renderItem={(data) => <Text>{data.item.name}</Text>}
/>
</View>
</View>
);
}
export default Home;
Edit:
Answering to the comment. My understanding of the docs that is incorrect because keyExtractor is for identifying the id and by your commented code unless your passed in data to FlatList has a property of key then that wont work.
Also if key is not a string it should be:
keyExtractor={(item) => item.key.toString()}

react-native-camera freeze when back on screen

I'm developing an application for a school project, and in this application I have a camera component in each view. When I go back on a view the camera freeze.
There is my code of one view:
class LoginView extends React.Component {
constructor(props) {
super(props);
}
togglePseudo = pseudo => {
const action = {type: 'USER_PSEUDO', value: pseudo};
this.props.dispatch(action);
};
render() {
const {navigate} = this.props.navigation;
const userPseudo = this.props.userPseudo;
return (
<View style={style.mainContainer}>
<RNCamera
style={style.backgroundCamera}
type={RNCamera.Constants.Type.back}
flashMode={RNCamera.Constants.FlashMode.on}
androidCameraPermissionOptions={{
title: "Permission d'utiliser la camera",
message: "L'application necessite l'autorisation de la camera",
buttonPositive: 'Autoriser',
buttonNegative: 'Refuser',
}}
/>
<View style={style.goContainer}>
<TouchableOpacity
style={style.backButton}
onPress={() => navigate('HomeView')}>
<Image source={require('assets/images/back-button.png')} />
</TouchableOpacity>
<View style={style.centeredElements}>
<Text style={style.titleMission}>Mission "Pc"</Text>
<View style={style.modalChoosePseudo}>
<Text style={style.modaltitle}>Choisir un pseudo</Text>
<TextInput
style={style.pseudoInput}
onChangeText={pseudo => this.togglePseudo(pseudo)}
value={userPseudo}
/>
{userPseudo !== '' ? (
<TouchableOpacity
style={style.validateButton}
onPress={() => navigate('InGame')}>
<Text style={style.buttonText}>Valider</Text>
</TouchableOpacity>
) : (
<TouchableOpacity
style={[style.validateButton, style.validateButtonDisabled]}
onPress={() =>
Alert.alert('Alerte', 'Veuillez entrer un pseudo')
}>
<Text
style={[style.buttonText, style.validateButtonDisabled]}>
Valider
</Text>
</TouchableOpacity>
)}
</View>
<Image
style={style.logoDimagine}
source={require('assets/images/logo_title_vertical.png')}
/>
</View>
</View>
</View>
);
}
}
I have already looked for solutions, so I tried what I found.
I've try to use componentDidMount with willFocus and willBlur, but it never detect them :
componentDidMount() {
const {navigation} = this.props;
navigation.addListener('willFocus', () =>
this.setState({focusedScreen: true}),
);
navigation.addListener('willBlur', () =>
this.setState({focusedScreen: false}),
);
}

react native drawer navigation on Press Item action

In my drawer navigator, there is log out button when I press on logout. I want to remove app_token but I don't know how.
I try to put something like this:
onItemPress:() => { AsyncStorage.removeItem('app_token')},
But it did not work.
const AppDrawerNavigator = createDrawerNavigator({
Logout: {
onItemPress:() => { AsyncStorage.removeItem('app_token')},
screen: HomePage,
navigationOptions: {
drawerIcon: (
<Image style={{ width: 30, height: 30 }}
source={require('./assets/IconDrawerNavigation/logout.png')} />
)
}
},
}
);
to solve this problem i use props called contentComponent from this props you can create your own drawer
import drawerContentComponents from './Drawer';
const AppDrawerNavigator = createDrawerNavigator({
Home: {screen: Home,}
},
},
{contentComponent: drawerContentComponents,}
);
//Drawer source code
//i use this library so i can restart the app and logout
import RNRestart from 'react-native-restart';
export default class drawerContentComponents extends Component {
_logout = () => {
AsyncStorage.removeItem('sale_id');
RNRestart.Restart();
}
render() {
return (
<View style={styles.container2}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('profile')} >
<View style={styles.screenStyle}>
<Image style={styles.iconStyle}
source={home} />
<Text style={styles.screenTextStyle}>My Profile</Text>
</View>
<View style={styles.underlineStyle} />
</TouchableOpacity>
<TouchableOpacity onPress={() => this.props.navigation.navigate('social')} >
<View style={styles.screenStyle}>
<Image style={styles.iconStyle}
source={home} />
<Text style={styles.screenTextStyle}>Contact US</Text>
</View>
<View style={styles.underlineStyle} />
</TouchableOpacity>
<TouchableOpacity onPress={this._logout} >
<View style={styles.screenStyle}>
<Image style={styles.iconStyle}
source={home} />
<Text style={styles.screenTextStyle}>Logout</Text>
</View>
</TouchableOpacity>
</View>
)
}
}

search box function using redux in react native

I am trying to make a search in my db items but all I receive is the following error: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Here is my code where I am creating the search page. JobItem I am using it in jobs page and everything is displaying correctly but here when I put the first letter in the search box I am getting the error.
import JobItem from './JobItem';
const { width, height } = Dimensions.get('window')
class SearchBar extends Component {
constructor(props) {
super(props)
this.state = {
text: '',
data: ''
}
}
static navigationOptions = {
headerVisible: false
}
filter(text) {
const data = this.props.jobs;
console.log(data);
const newData = data.filter(function (job) {
const itemData = job.title.toUpperCase()
const textData = text.toUpperCase()
return itemData.indexOf(textData) > -1
})
this.setState({
data: newData,
text: text,
})
}
deleteData() {
this.setState({ text: '', data: '' })
}
_renderJobs(job) {
return this.props.jobs.map((job) => {
return (
<JobItem
key={job._id}
title={job.title}
shortDescription={job.shortDescription}
logo={job.avatar}
company={job.company}
id={job._id}
city={job.location[0].city}
postDate={job.postDate}
dispatch={this.props.dispatch}
onPress={() => this.onJobDetails(job)}
/>
)
})
}
render() {
const { goBack } = this.props.navigation
return (
<View style={styles.container}>
<View style={styles.header}>
<FontAwesome
name="magnify"
color="grey"
size={20}
style={styles.searchIcon}
/>
<TextInput
value={this.state.text}
onChangeText={(text) => this.filter(text)}
style={styles.input}
placeholder="Search"
placeholderTextColor="grey"
keyboardAppearance="dark"
autoFocus={true}
/>
{this.state.text ?
<TouchableWithoutFeedback onPress={() => this.deleteData()}>
<FontAwesome
name="clock-outline"
color="grey"
size={20}
style={styles.iconInputClose}
/>
</TouchableWithoutFeedback>
: null}
<TouchableWithoutFeedback style={styles.cancelButton} onPress={() => goBack()}>
<View style={styles.containerButton}>
<Text style={styles.cancelButtonText}>Cancel</Text>
</View>
</TouchableWithoutFeedback>
</View>
<ScrollView>
<FlatList
style={{ marginHorizontal: 5 }}
data={this.state.data}
numColumns={3}
columnWrapperStyle={{ marginTop: 5, marginLeft: 5 }}
renderItem={({ job }) => this._renderJobs(job)}
/>
</ScrollView>
</View>
)
}
}
Please anyone help me with this.