I am new to React Native and I am facing a problem when i try to build a flat list that navigate to another screen with the item details when pressing on a list item. I am using redux and react-native-router-flux to navigate between screens. the flat list is rendering but I can not navigate to another screen when I press on item.
here is my code:
class MyListItem extends React.PureComponent {
_onPress = () => {
this.props.onPressItem(this.props.item);
};
render() {
return (
<TouchableOpacity
{...this.props}
onPress={this._onPress}>
<View style={styles.GridViewContainer} >
<Text style={styles.GridViewTextLayout} >{this.props.item.name}</Text>
</View>
</TouchableOpacity>
);
}
}
class CustomersList extends Component {
componentWillMount() {
this.props.getCustomers();
}
componentDidUpdate(prevProps) {
if (prevProps.customers !== this.props.customers) {
this.props.getCustomers();
}
}
_keyExtractor = (item, index) => item._id;
_onPressItem = (item) => {
Actions.customerShow({ customer: item });
};
_renderItem = ({ item }) => (
<MyListItem
id={item._id}
item={item}
onPressItem={() => this._onPressItem(item)}
title={item.name}
/>
);
render = () => {
return (
<View style={styles.container}>
<FlatList
data={this.props.customers}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
extraData={this.state}
numColumns={3}
/>
</View>
);
}
}
const mapStateToProps = (state) => {
const customers = state.customers;
console.log(customers);
debugger
return { customers };
};
export default connect(mapStateToProps, {
getCustomers
})(CustomersList);
And here is the axios api :
export const getCustomers = () => {
debugger;
return (dispatch) => {
dispatch(setCustomerLoading)
axios
.get('https://calm-sands-26165.herokuapp.com/api/customers')
.then(res =>
dispatch({
type: GET_CUSTOMERS,
payload: res.data,
})
)
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: null
})
);
};
}
the routing stacks:
const RouterComponent = () => {
return (
<Router >
<Scene key="root" hideNavBar>
<Scene key="auth">
<Scene key="login" component={LoginForm} title="Please Login" initial />
</Scene>
<Scene key="main">
<Scene
onRight={() => Actions.customerCreate()}
rightTitle="Add"
key="customersList"
component={CustomersList}
title="Customers"
initial
/>
<Scene key="customerCreate" component={CustomerCreate} title="Create Customer" />
<Scene key="customerShow" component={CustomerShow} title="Show Customer" />
</Scene>
</Scene>
</Router>
);
};
Thanx in advance,
The error you are getting is caused when the data source prvided to FlatList
is not an array. In your case, this.props.customers
is undefined until the function this.props.getCustomers()
is returned.
What I would suggest is to use the state to render the flatlist in your CustomersList
component. And update the state when the results are returned from the axios async call this.setState({customers : nextProps.customers})
which will rerender the FlatList
with the customers array.
class CustomersList extends Component {
constructor(props){
super(props);
this.state = {
customers : []
};
}
...
render = () => {
return (
<View style={{flex:1}}>
{this.state.customers.length > 0 ?
<FlatList
data={this.state.customers}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
extraData={this.state}
numColumns={1}
/> :
<View style={styles.container}>
<ActivityIndicator size={'large'}/>
</View>
}
</View>
);
}
}
As for your navigation, I did test your code myself and it worked :) (As you can see I used <ActivityIndicator />
to render when the list is still fetching.