React Navigation not passing props - javascript

I have a component that takes an object and passes it to a new screen upon navigating to the screen. However, when I go to the next screen the object passed is undefined. What am I doing wrong here? I have done the exact same thing with another component and it works perfectly fine, but on this component, it isn't passing the parameter properly. Is there something else I need to configure in the navigator?
GoalCard.JS
import * as React from 'react';
import 'react-native-get-random-values';
import { v4 as uuidv4 } from 'uuid';
import { useNavigation } from "#react-navigation/core";
import { Card, Chip, Divider, Paragraph, Text, Title } from 'react-native-paper';
const GoalCard = ({ item }) => {
const navigation = useNavigation();
const goals = JSON.parse(item.Goals);
const tasks = JSON.parse(item.GoalTasks);
const [goalsData, setGoalsData] = React.useState(
{
GoalName: item.GoalName,
GoalID: item.GoalID,
GoalDescription: item.GoalDescription,
GoalComplete: item.GoalComplete,
GoalTasks: tasks,
Goals: goals,
UserID: item.UserID,
createdAt: item.createdAt,
updatedAt: item.updatedAt
}
);
return(
<Card className="card">
<Card.Content>
<Title>Goal Set: {item.GoalName}</Title>
<Divider/>
<Paragraph>
<Chip
onPress={() => {
navigation.navigate(
'Goals', {
goalsData: goalsData
});
}}
>
Edit
</Chip>
<Text onPress={() => console.log(goalsData)}>Log</Text>
<Text>Description: {item.GoalDescription}</Text>
<Divider/>
{Object.entries(goals).map(obj => (
<Text key={uuidv4()}>{obj[1].goal}{" "}</Text>
))}
</Paragraph>
</Card.Content>
</Card>
);
}
export default GoalCard;
GoalScreen.js
Pressing "Log" as seen in this file returns undefined
import React from "react";
import { ScrollView, View } from "react-native";
import { Text } from "react-native-paper";
import { MainStyles } from "../../styles/Styles";
const GoalScreen = ({ route }) => {
const { goalData } = route.params;
return (
<ScrollView>
<View style={MainStyles.col}>
<Text onPress={() => console.log(goalData)}>Log</Text>
</View>
</ScrollView>
);
};
export default GoalScreen;

There is a typo ... You are setting
goalsData: goalsData
But you are trying to read as below
const { goalData } = route.params;
try
const { goalsData } = route.params;

Related

How to make a react icon with ternary linked to random api data global

I have a component that is gathering random data on each call from an api. In this component I have an icon that is rendered depending on what the weather is like from the api. I'm wanting to render only the icon from this component in another component without having to make another api call.
This is my weather component:
import axios from 'axios';
import { useEffect, useState } from 'react';
import { Weather } from '../types';
import { MdWbSunny } from 'react-icons/md';
import { IoIosPartlySunny } from 'react-icons/io';
import { BsFillCloudSnowFill } from 'react-icons/bs';
import { Title, Text, Container } from '#mantine/core';
const WeatherComponent = () => {
const [weather, setWeather] = useState<Weather | null>();
const fetchWeatherData = async () => {
const response = await axios.get('http://mock-api-call/weather/get-weather');
setWeather(response.data.result.weather);
};
useEffect(() => {
fetchWeatherData();
}, []);
return (
<Container>
<Title order={2}>
{weather?.forcast === 'Sunny' ? (
<MdWbSunny data-testid="sunny" />
) : weather?.forcast === 'Snowing' ? (
<BsFillCloudSnowFill data-testid="snowing" />
) : (
<IoIosPartlySunny data-testid="overcast" />
)}
</Title>
<Text size="xl" data-testid="forcast">
{weather?.forcast}
</Text>
<Text size="lg" data-testid="temp">
Temp: {`${weather?.min} to ${weather?.max}`}
</Text>
<Text size="md" data-testid="description">
{weather?.description}
</Text>
</Container>
);
};
export default WeatherComponent;
if I could export weather from this component into my other component I think I would be able to move the ternary operators into the other component.
How can I export this data?

Not sure how to include function in useEffect

I am trying to mount a function within useEffect, how would I call this function within useEffect, I am not sure?
Initially useEffect is written as following in the app-
useEffect(() => {
CognitensorEndpoints.getDashboardList({
dispatchReducer: dispatchDashboards,
});
CognitensorEndpoints.getList({
dispatchReducer: dispatchDashboards,
});
},[]);
Then when I include useEffect as below, it returns errors ('Cannot read property 'filter' of undefined') -
useEffect(() => {
console.log('abcd');
setLoading();
CognitensorEndpoints.getDashboardList({
dispatchReducer: dispatchDashboards,
});
CognitensorEndpoints.getList({
dispatchReducer: dispatchDashboards,
});
},[]);
How do I correctly include 'setLoading()' within useEffect?
Here's the full app code-
import React, { useState, useEffect, useReducer } from 'react';
import { View, Text, StyleSheet, FlatList, ActivityIndicator, Keyboard, Button } from 'react-native';
import { Searchbar } from 'react-native-paper';
import { theme } from '../theme';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { apiStateReducer } from '../reducers/ApiStateReducer';
import CognitensorEndpoints from '../services/network/CognitensorEndpoints';
import DefaultView from '../components/default/DefaultView';
import DashboardListCard from '../components/DashboardListCard';
import DashboardHeader from '../components/DashboardHeader';
import DashboardGridCard from '../components/DashboardGridCard';
import {
NavigationContainer,
useFocusEffect,
} from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
const AppHeader = ({
scene,
previous,
navigation,
searchIconVisible = false,
item,
index,
onPress
}) => {
const [dashboards, dispatchDashboards] = useReducer(apiStateReducer, {
data: [],
isLoading: true,
isError: false,
});
const [gridView, setGridView] = useState(false);
const toggleGridView = () => {
setGridView(!gridView);
};
const [filtered, setFiltered] = useState([]);
const setLoading = () => {
const messages = dashboards.data.message.filter((item) => {
const title = item.dashboardTitle || item.dashboardName;
return title.toLowerCase();
});
setFiltered(messages);
console.log(filtered);
};
const dropShadowStyle = styles.dropShadow;
const toggleSearchVisibility = () => {
navigation.navigate('Search');
};
useEffect(() => {
console.log(abcd);
setLoading();
CognitensorEndpoints.getDashboardList({
dispatchReducer: dispatchDashboards,
});
CognitensorEndpoints.getList({
dispatchReducer: dispatchDashboards,
});
},[]);
return (
<>
<View style={styles.header}>
<View style={styles.headerLeftIcon}>
<TouchableOpacity onPress={navigation.pop}>
{previous ? (
<MaterialIcons
name="chevron-left"
size={24}
style={styles.visible}
/>
) : (
<MaterialIcons
name="chevron-left"
size={24}
style={styles.invisible}
/>
)}
</TouchableOpacity>
</View>
{filtered.map(item => (
<Text style={styles.headerText}>
{item.dashboardTitle}
</Text>
))}
<View style={styles.headerRightIconContainer}>
{searchIconVisible ? (
<TouchableOpacity
style={[styles.headerRightIcon, dropShadowStyle]}
onPress={toggleSearchVisibility}>
<MaterialIcons name="search" size={24} style={styles.visible} />
</TouchableOpacity>
) : (
<View style={styles.invisible} />
)}
</View>
</View>
</>
);
};
The error is because dashboards.data.message is undefined or null. Please re-check the data.

Too many re-renders on search API

I am new to this so I hope this is the right place to get help!
As titled, executing this code is giving me the "Too many re-renders" error on React.
I have tried going through all lines and checking my hooks repeatedly, but nothing seems to work.
I am guessing this is happening due to useEffect, so pasting the code for the relevant components below:
UseResults:
import { useEffect, useState } from 'react';
import yelp from '../api/yelp';
export default () => {
const [results, setResults] = useState([]);
const [errorMessage, setErrorMessage] = useState('');
const searchApi = async () => {
try {
const response = await yelp.get('/search', {
params: {
limit: 50,
term,
location: 'san francisco'
}
});
setResults(response.data.businesses);
} catch (err) {
setErrorMessage('Something went wrong')
}
};
useEffect(() => {
searchApi('pasta');
}, []);
return [searchApi, results, errorMessage];
}
SearchScreen:
import React, { useState } from 'react';
import { Text, StyleSheet } from 'react-native';
import { ScrollView } from 'react-native-gesture-handler';
import ResultsList from '../components/ResultsList';
import SearchBar from '../components/SearchBar';
import useResults from '../hooks/useResults';
const SearchScreen = (navigation) => {
const [term, setTerm] = useState('');
const [searchApi, results, errorMessage] = useResults();
const filterResultsByPrice = (price) => {
return results.filter(result => {
return result.price === price;
});
};
return <>
<SearchBar
term={term}
onTermChange={setTerm}
onTermSubmit={searchApi()}
/>
{errorMessage ? <Text>{errorMessage}</Text> : null}
<Text>We have found {results.length} results</Text>
<ScrollView>
<ResultsList
results={filterResultsByPrice('$')}
title="Cost Effective"
navigation={navigation}
/>
<ResultsList
results={filterResultsByPrice('$$')}
title="Bit Pricier"
navigation={navigation}
/>
<ResultsList
results={filterResultsByPrice('$$$')}
title="Big Spender"
navigation={navigation}
/>
</ScrollView>
</>
};
const styles = StyleSheet.create({});
export default SearchScreen;
ResultsList:
import React from 'react';
import { View, Text, StyleSheet, FlatList } from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
import ResultsDetail from './ResultsDetail';
const ResultsList = ({ title, results, navigation }) => {
return (
<View style={styles.container} >
<Text style={styles.title}>{title}</Text>
<FlatList
horizontal
showsHorizontalScrollIndicator={false}
data={results}
keyExtractor={result => result.id}
renderItem={({ item }) => {
return (
<TouchableOpacity onPress={() => navigation.navigate('ResultsShow')}>
<ResultsDetail result={item} />
</TouchableOpacity>
)
}}
/>
</View>
);
};
const styles = StyleSheet.create({
title: {
fontSize: 18,
fontWeight: 'bold',
marginLeft: 15,
marginBottom: 5
},
container: {
marginBottom: 10
}
});
export default ResultsList;
TIA!

The icon disappears and null in my terminal

I updated my code thanks to your help. When I launch the app with Expo, I have two errors:
1/ I lost my scan icon which does not appear in my screen. This icon appeared previously. The idea is to scan some barcodes in order to display relevant data stemming from products.
2/ In my terminal, when the app is launched with Expo, I have this message: Array[], null, null
I would appreciate your comments concerning my issues. All the best,
Here is my new code:
import React, { useState, useEffect } from "react";
import {
StyleSheet,
Text,
View,
FlatList,
Button,
AsyncStorage,
} from "react-native";
import { useNavigation } from "#react-navigation/core";
import { TouchableOpacity } from "react-native-gesture-handler";
import { FontAwesome5 } from "#expo/vector-icons";
import { MaterialCommunityIcons } from "#expo/vector-icons";
import { ActivityIndicator } from "react-native-paper";
function ProductsScreen() {
const navigation = useNavigation();
const [data, setData] = useState([]);
const [isLoading, setisLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
const data = await AsyncStorage.getItem("userData");
setData(data);
setisLoading(false);
};
fetchData();
}, []);
console.log(data);
return isLoading ? (
<ActivityIndicator />
) : (
<>
{data ? (
<FlatList
data={dataArray}
keyExtractor={(item) => item.name}
renderItem={({ item }) => (
<>
<Text>{item.brand}</Text>
<View style={styles.scan}>
<MaterialCommunityIcons
name="barcode-scan"
size={40}
color="black"
onPress={() => {
navigation.navigate("CameraScreen");
}}
/>
</View>
</>
)}
/>
) : null}
</>
);
}
export default ProductsScreen;
Can you explain a little more? Having trouble making Asyncstroge setItem? If the vector icon is not visible,
react-native run-android,
You can try doing npm start --reset-cache.

Reselect selector function not executing

I'm trying to use reselect to select if a form is valid but the function that selects the validity never runs:
import { createSelector } from 'reselect'
import { getSelectedItems } from '../categories/Categories'
const categoriesSelector = state => state.get('searchForm').get('categories')
const placeSelector = state => state.get('searchForm').get('location').place
export const makeSelectIsValid = () => createSelector(
categoriesSelector,placeSelector,
(categories,place) => getSelectedItems(categories).length > 0 && place !== {}
)
I import it into a component and try to use it in a pre-existing mapStateToProps:
import { makeSelectIsValid } from './searchFormIsValid.selector'
const mapStateToProps = (state) => ({
isMenuOpen: state.get('searchPage').get('isMenuOpen'),
searchFormIsValid: makeSelectIsValid()
})
And I try to at this stage just display the value:
<Title style={styles.title}>{props.searchFormIsValid.toString()}</Title>
But what gets displayed is a function turned into a string.
Where am I going wrong?
Here is the whole component that uses it just in case it is relevant:
import { ScrollView, StyleSheet, View } from 'react-native'
import {
Container,
Button,
Text,
Header,
Body,
Right,
Left,
Title
} from 'native-base'
import React from 'react'
import Keywords from '../keywords/Keywords'
import Categories from '../categories/Categories'
import Location from '../location/Location'
import DistanceSlider from '../distanceSlider/DistanceSlider'
import Map from '../map/Map'
import Drawer from 'react-native-drawer'
import { connect } from 'react-redux'
import { toggleMenu } from './searchPage.action'
import { styles } from '../../style'
import searchPageStyle from './style'
import { makeSelectIsValid } from './searchFormIsValid.selector'
const mapStateToProps = (state) => ({
isMenuOpen: state.get('searchPage').get('isMenuOpen'),
searchFormIsValid: makeSelectIsValid()
})
const mapDispatchToProps = (dispatch) => ({
toggleMenu: () => {
dispatch(toggleMenu())
}
})
let SearchPage = (props) => {
const menu = (
<Container>
<Header style={styles.header}>
<Left>
<Button transparent>
</Button>
</Left>
<Body>
<Title style={styles.title}>Search{/*props.searchFormIsValid.toString()*/}</Title>
</Body>
<Right>
</Right>
</Header>
<Container style={styles.container}>
<ScrollView keyboardShouldPersistTaps={true}>
<Categories />
<View style={searchPageStyle.locationContainer}>
<Location />
</View>
<DistanceSlider />
<Keywords />
<Button
block
style={searchPageStyle.goButton}
//disabled={!props.searchFormIsValid}
onPress={props.toggleMenu}>
<Text>GO</Text>
</Button>
</ScrollView>
</Container>
</Container>
)
return (
<Drawer open={props.isMenuOpen} content={menu}>
<Container style={mapStyles.container}>
<Map />
</Container>
</Drawer>
)
}
SearchPage.propTypes = {
toggleMenu: React.PropTypes.func.isRequired,
isMenuOpen: React.PropTypes.bool.isRequired,
searchFormIsValid: React.PropTypes.bool.isRequired
}
SearchPage = connect(
mapStateToProps,
mapDispatchToProps
)(SearchPage)
export default SearchPage
const mapStyles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
height: 400,
width: 400,
justifyContent: 'flex-end',
alignItems: 'center',
}
})
Since makeSelectIsValid is a selector factory, it should be used like this:
import { makeSelectIsValid } from './searchFormIsValid.selector'
const mapStateToProps = (state) => {
// Make a selector instance
const getSelectIsValid = makeSelectIsValid();
return {
isMenuOpen: state.get('searchPage').get('isMenuOpen'),
searchFormIsValid: getSelectIsValid(state)
};
}
Extra consideration: given your scenario, the selector factory is unnecessary, since you might directly expose getSelectIsValid selector avoiding selector instantiation in mapStateToProps.

Categories

Resources