2
votes

I am trying to create stateless component to display a Flatlist and I am struggling with the navigation.

This is my 'main' app.js, stripped down:

import React from 'react';
import { AppRegistry, FlatList, ActivityIndicator, Text, View, Image, StyleSheet } from 'react-native';
import { StackNavigator } from 'react-navigation'
import Strip from '../components/Strip'

export default class FetchData extends React.Component {

    constructor(props){
        super(props);
        this.state ={ isLoading: true}
    }

    componentDidMount(){
        ...
    }


    render(){
        if(this.state.isLoading){
            ...
        }
        return (
            <View>
                <Strip props={this.state.dataSource.strips} />
            </View>
        )
    }
}

And this is the component:

import React from 'react';
import { FlatList, Text, View, Image, StyleSheet, TouchableOpacity } from 'react-native';

renderItem = ({item}) => (
    <TouchableOpacity onPress={() => this.props.navigation.navigate('Details')} >
        <View style={{width: 136}}>
            ...
            <Text>some text</Text>
        </View>
    </TouchableOpacity>
);

const Strip = (props) => {
    return Object.keys(props).map(function(key, i) {
        return Object.keys(props[key]).map((strips, i) => {
            var strip = props[key][strips];
            return(
                <View>
                    <Text>{strip.title}</Text>
                    <FlatList horizontal
                        data={strip.someobjects}
                        renderItem={({item}) => this.renderItem(item)}
                    />     
                </View>
            )
        });
    })
}

export default Strip;

The list is displayed but, of course, when I touch an item I get the 'undefined is not an object (evaluating '_this.props.navigation')' error.

I know that I can't use this.props.navigation.navigate on a stateless component but I just don't understand how I can pass the navigation props via a flatlist in a stateless component.

It has to be something really simple like using navigate('Details') and put const { navigate } = this.props.navigation; somewhere. But where?

2

2 Answers

1
votes

Instead of navigate from Strip component, provide an onPress handler to Strip and navigate from there. If FetchData is part of StackNavigator then you could easily navigate from this component.

Consider following example

...
export default class FetchData extends React.Component {
 ...
 handleOnPress = () => {
  this.props.navigation.navigate('Details')
 }

 render() {
  if(this.state.isLoading){
   ...
  }
  return (
   <View>
    <Strip 
     props={this.state.dataSource.strips} 
     onPress={this.handleOnPress} 
    />
   </View>
  );
 }
}

In the Strip component, you can bind the onPress handler

 const Strip = (props) => {
  renderItem = ({item}) => (
   <TouchableOpacity onPress={props.onPress} >
    <View style={{width: 136}}>
     ...
    <Text>some text</Text>
   </View>
  </TouchableOpacity>
 );

 return Object.keys(props).map(function(key, i) {
  return Object.keys(props[key]).map((strips, i) => {
   var strip = props[key][strips];
    return(
     <View>
      <Text>{strip.title}</Text>
       <FlatList horizontal
         data={strip.someobjects}
         renderItem={({item}) => renderItem(item)}
       />     
      </View>
     )
  });
})
}

Hope this will help!

0
votes

Define a function for navigation in parent and pass it to child via props.

Eg:

Parent


parentNavigate(destination){
 this.props.navigation.navigate(destination);
}

render(){
        if(this.state.isLoading){
            ...
        }
        return (
            <View>
                <Strip props={this.state.dataSource.strips} parentNavigate={(destination) => this.parentNavigate(destination)}/>
            </View>
        )
    }

Child


renderItem = (item, parentNavigate) => (
    <TouchableOpacity onPress={parentNavigate('Details')} >
        <View style={{width: 136}}>
            ...
            <Text>some text</Text>
        </View>
    </TouchableOpacity>
);

const Strip = (props, parentNavigate) => {
    return Object.keys(props).map(function(key, i) {
        return Object.keys(props[key]).map((strips, i) => {
            var strip = props[key][strips];
            return(
                <View>
                    <Text>{strip.title}</Text>
                    <FlatList horizontal
                        data={strip.someobjects}
                        renderItem={(item, parentNavigate) => this.renderItem(item, parentNavigate)}
                    />     
                </View>
            )
        });
    })
}