enter image description hereWhen using navigation v5, I encounter an error can not read property navigate of undefined
const Categories=({navigation})=> {
return (
<View >
<Text style={Styles.TextCategories}>دسته بندی ها</Text>
{/* ---------------------------------------------------------------لایه کلی صفحه---------------------------------- */}
<View style={Styles.View}>
{/* --------------------------------------------------------------- لایه دکمه ها---------------------------------- */}
<Button style={Styles.Button} onPress={()=>navigation.navigate('Homesales')}>
<MaterialIcons name="waves" size={30} color={"#0c7656"} />
<Text style={Styles.Text}>زمین</Text>
</Button>
const Home=()=>{
useEffect(()=>{
axios.get('https://jsonplaceholder.typicode.com/posts').then((response)=>console.log(response.data)).catch((e)=>console.log(e))
},[])
return (
<Categories/>
);
}
export default React.memo(Home);
why don't you use navigation hook of react-navigation-v5?? instead of passing navigation as prop try to "useNavigation()" hook, this way you will have access to a valid navigation object from anywhere
const navigation=useNavigation()
for using navigation
navigation.navigate('')
You are passing a object that does not has property 'navigation' to component Categories
You need to check at the parent component, seem that props/navigation is null here.
Related
I am working with react native and expo.cli and would like to know how I can manage to add a handle to a TouchableOpacity, I have the following component:
function MainModal (){
return(
<>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity
onPress={this.TouchableOpacity}
>
<Text>Volver</Text>
</TouchableOpacity>
</View>
</>
What I want to do is make a reference to this specific TouchableOpacity when it is selected, but when I use a "this" nested in the component I get the following error: Undefined is not an object (Evaluating 'this.TouchableOpacity') I know maybe This question is a bit of a novice and has more to do with how 'this' works in javascript than with React Native itself, however I can't find a way to make a reference to the selected object so that it executes something when selected. How could I do it?
You can use React.useRef() hook to create a reference to that element so you can access then to it. The idea you have of this is not the actual this. This might refer to the global object (in not strict) and might be undefined in strict mode. If you want to use this in a component I recommend you to create a class component instead of a function one. See this in MDN to learn more of it.
Anyway, the use of ref in a functional component would be this:
function MainModal (){
const touchableReference = React.useRef()
const handleTouchableClick = () => {
console.log(touchableReference.current)
//
// Outputs HTMLDivElement...
//
}
return(
<>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity
ref={touchableReference}
onPress={() => handleTouchableClick()}
>
<Text>Volver</Text>
</TouchableOpacity>
</View>
</>
)
}
One standard way of passing event handler in functional component is as follows
function MainModal (props){
const onPress1 = useCallback(()=>console.log); // created inside the componet
const {onPress2} = props; // passed from props
const {onPress3} = useSomeHook(); // from context/hook
return(
<>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity
onPress={onPress1}
>
<Text>Volver</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={onPress2}
>
<Text>Volver</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={onPress3}
>
<Text>Volver</Text>
</TouchableOpacity>
</View>
</>
);
}
The behaviour of this works the same in react and react-native. React functional component is executed during the render phase and you are not suppose to work with this here, given that you do not understand when and where it is called.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
I want to pass the title of a React Native Button component into a neighbouring function. I am using React Native functional components only for this application.
Here's the component. I would like to pass the title of the button pressed by the user, which will be either 'English' or 'Arabic', into the function submitLanguageSelection so that I can then save that value into useLocalStorage(), a custom hook I wrote to handle AsyncStorage, so that the next time the user uses the app, their language choice will be persisted, and they will not be shown the ChooseYourLanguageScreen again.
All help appreciated, thank you.
const ChooseYourLanguageScreen = ({ navigation }) => {
const [saveData, storedValue, errorMessage] = useLocalStorage();
const [userSelectedLanguage, setUserSelectedLanguage] = React.useState('');
const submitLanguageSelection = () => {
//TODO: receive params from onPress
//TODO: save the data locally
//TODO: navigate to welcome screen
};
return (
<View style={styles.container}>
{errorMessage ? <Text>{errorMessage}</Text> : null}
<Text style={styles.text}>This is the Choose Your Language Screen</Text>
<View style={styles.buttons}>
<View>
<Button
title={'English'}
onPress={() => submitLanguageSelection()}
/>
</View>
<View>
<Button title={'Arabic'} onPress={() => submitLanguageSelection()} />
</View>
</View>
</View>
);
};
You can simply pass it to the function
<Button title={'Arabic'} onPress={() => submitLanguageSelection('Arabic')} />
And access like below
const submitLanguageSelection = (language) => {
console.log(language);
};
Getting data from a sibling component is an anti-pattern.
The source of the knowledge of the language options is the ChooseYourLanguageScreen component (as seems from your snippet), so it should hold the list of available languages. Having that, you can just iterate through them and render the appropriate components:
<View style={styles.buttons}>
{languages.map((language) => (
<View key={language}>
<Button
title={language}
onPress={() => submitLanguageSelection(language)}
/>
</View>
))}
</View>
I am grabbing data from an API to display an image based on the API value. The following code works perfect IF there is an image in the object. If an API item does not have an image the app throws an "Undefined is not an object" error.
<View>
<Image source={{uri:props.enclosures[0].url}} style={styles.mainPhoto} />
</View>
I have tried the following code to check if the value exists first, but it still throws exact same error if an API item does not have image.
<View>
{props.enclosures[0].url ?
<Image source={{uri:props.enclosures[0].url}} style={styles.mainPhoto} />
:
<Text>No Image</Text>
}
</View>
If you are going to access multiple properties of a nested object, you should check everything, like so
<View> // Checking everthing so it never throws an error
{props.enclosures && props.enclosures[0] && props.enclosures[0].url ?
<Image source={{uri:props.enclosures[0].url}} style={styles.mainPhoto} />
:
<Text>No Image</Text>
}
</View>
To prevent undefined error you can also use path from Ramda library. It allows you to safely access any nested object/array.
const MyComponent = (props) => {
const apiImage = path(["enclosures", 0, "url"], props);
return {
<View>
{apiImage ?
<Image source={{uri:apiImage}} style={styles.mainPhoto} />
:
<Text>No Image</Text>
}
</View>
}
}
I created a basic component such as:
export default (props) => (
<TouchableOpacity {...props} style={styles.button}>
{props.title && <Text style={styles.text}>{props.title}</Text>}
{props.icon && <Icon name={props.icon} />}
</TouchableOpacity>
);
I can then call it with <Component title="Home" icon="home" /> for instance.
The problem is that passing {...props} to TouchableOpacity generate errors because it does not recognize title nor icon properly.
For instance:
JSON value 'Home' of type NSString cannot be converted to...
Is there a way to filter props so that I only pass valid ones for TouchableOpacity?
Transferring Props
Sometimes it's fragile and tedious to pass every property along. In that case you can use destructuring assignment with rest properties to extract a set of unknown properties.
List out all the properties that you would like to consume, followed by ...other.
var { checked, ...other } = props;
This ensures that you pass down all the props EXCEPT the ones you're
consuming yourself.
function FancyCheckbox(props) {
var { checked, ...other } = props;
var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
// `other` contains { onClick: console.log } but not the checked property
return (
<div {...other} className={fancyClass} />
);
}
ReactDOM.render(
<FancyCheckbox checked={true} onClick={console.log.bind(console)}>
Hello world!
</FancyCheckbox>,
document.getElementById('example')
);
Like Paul Mcloughlin, I would recommend using object destructuring along with a rest parameter. You can destructure your props object directly in your function parameters like so:
({title, icon, ...remainingProps}) => (...)
This extracts the title and icon props from your props object and passes the rest as remainingProps.
Your complete component would be:
export default ({title, icon, ...remainingProps}) => (
<TouchableOpacity {...remainingProps} style={styles.button}>
{title && <Text style={styles.text}>{title}</Text>}
{icon && <Icon name={icon} />}
</TouchableOpacity>
);
So Basically I am getting error in the title which is related to the navigator.
The error pops up when I press on the Icon.
What I basically want to do is make a Tab bar at the top that switches between three different views: feed, wiki, and message board
Here is my index.android.js: (imports Nav)
_renderScene(route, navigator) {
var globalNavigatorProps = {navigator};
switch(route.ident) {
case "FeedView":
return(
<Feed
{...globalNavigatorProps}
/>
);
case "WikiView":
return(
<View>
<Text>
{'Hello'};
</Text>
</View>
);
case "BoardView":
return(
<View>
<Text>
{'Hello'};
</Text>
</View>
);
default:
console.log(`Something went wrong ${route}`);
}
}
render(){
return(
<View>
<Nav />
<Navigator
initialRoute={{ident:"Feed"}}
ref="appNavigator"
renderScene={ this._renderScene }
/>
</View>
);
}
Here is my Nav.js:
constructor(props){
super(props);
}
render(){
console.log(this.props.navigator);
return(
<View style={{flexDirection: "column"}}>
<View style={styles.nav}>
<Icon onPress={(event) => this.props.navigator.push({ident: "Feed"})} name="newspaper-o" size={22}/>
<Icon name="wikipedia-w" size={22}/>
<Icon name="comments" size={22}/>
</View>
<View style={styles.divider}/>
</View>
);
}
_changeView(type){
}
I dont think this is the issue, but the renderScene function won't be bound to the react component.
Try turning renderScene={ this._renderScene } into renderScene={ this._renderScene.bind(this) }
If you are trying to implement a tabbed view there are better ways of doing it you can always use an open source module such as this one https://github.com/skv-headless/react-native-scrollable-tab-view
the developer has made it in such a way that it is easy to use and the example is good enough to get through most of the part.
So instead of creating such components yourself what I would suggest is to use the modules made by the community.
Hope my answer was helpful.
this error always occurs when you didnt bind(this),check you Icon module onPress method