I am trying to render data from an API using a FlatList.
I can't get anywhere. I have a lot of trouble filling in the DATA and renderItem fields.
Could you help me ?
Thank you :)
import React from "react";
import { Text, ActivityIndicator, FlatList, View } from "react-native";
import axios from "axios";
export default class Results extends React.Component {
constructor(props) {
super(props);
//console.log('state',this.props)
this.state = {
city: "Montpellier", //this.props.city,
report: null, // Données de l'API
};
this.fetchWeather();
}
fetchWeather() {
axios
.get(
"https://api.openweathermap.org/data/2.5/weather?q=" +
this.state.city +
"&appid=9fce19ee0d267aa48afdf331bb1668da",
)
.then((response) => {
this.setState({ report: response.data });
//console.log(response.data)
});
}
render() {
const DATA = this.state.report;
if (this.state.report === null) {
return <ActivityIndicator size="large" color="red" />;
} else {
return (
<FlatList data={DATA} renderItem={<Text> {this.state.report.id} </Text>} keyExtractor={(item) => item.id} />
);
}
}
}
renderItem prop basically passes each item in your data to the function provided so that you can render them accordingly in the list. Changing you flatlist like this should work.
render() {
const {report} = this.state;
if (report === null) {
return <ActivityIndicator size="large" color="red" />;
} else {
return (
<FlatList
data={report}
renderItem={(reportItem) => <Text> {reportItem.id} </Text>}
keyExtractor={(item) => item.id} />
);
}
}
There are two mistakes in your Flatlist.
renderItem must be a function that returns all your JSX code
Since you already provided the Flatlist with data, you don't need to refer to this.state.report.id again, you can simply replace it with {item.id}.
So your Flatlist should look like this:
<FlatList
data={DATA}
keyExtractor={(item) => item.id}
renderItem={(item) => {
return (
<Text> {item.id} </Text>)
}}
</FlatList>
So the idea is that the FlatList will take in an array (<FlatList data={DATA} ...) and will automatically go through the items one by one. But it does not know how to render the actual UI for each item. For that we are giving a function which will transform each item into a UI element. This is the function that we are missing.
So
import React from "react";
import { Text, ActivityIndicator, FlatList, View } from "react-native";
import axios from "axios";
export default class Results extends React.Component {
.
.
.
render() {
const DATA = this.state.report;
if (this.state.report === null) {
return <ActivityIndicator size="large" color="red" />;
} else {
return (
<FlatList data={DATA} renderItem={function (item) {
return <Text> {item.id} </Text>
}} keyExtractor={(item) => item.id} />
);
}
}
}
As per the documentation, what they mean is that this function will be called and each item will be passed into it. The item shape will be of the same shape as DATA[0] (essentially any object in that array).
In the docs, they have this snippet,
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
This essentially means that each object in the array is of shape
{
title: "some title"
}
That is called object destructuring, and it is easy to understand if you google for it :)
Related
I've been trying to replace a view in React Native, but to no success. The app closes without errors whenever I try <TouchableOpacity onPress={() => {handleChangeMyView();}}> :
What am I doing wrong? How can I make it work?
Thank you all in advance.
import React, {
useState
} from 'react';
import {
SafeAreaView,
View,
TouchableOpacity,
} from 'react-native';
import MyInitialView from './MyInitialView';
const SiteContainer = () => {
let MyDynamicView = () => {
return (
<View></View>
);
};
const [MyDynamicViewArea, setMyDynamicViewArea] = useState(MyInitialView);
const handleChangeMyView = () => {
setMyDynamicViewArea(MyDynamicView);
};
return (
<SafeAreaView>
{MyDynamicViewArea}
<TouchableOpacity onPress={() => {handleChangeMyView();}}>
<View>
<FontAwesome name="quote-left"></FontAwesome>
</View>
</TouchableOpacity>
</SafeAreaView>
);
};
export default SiteContainer;
MyInitialView :
import React from 'react';
import {
View
} from 'react-native';
export default function MyInitialView() {
return (
<View></View>
);
}
You can use boolean value for viewing MyInitialView using useState
const [toViewMyInitialView, setToViewMyInitialView] = useState(false);
and in handleChangeMyView function set the above value as true
const handleChangeMyView = () => {
setToViewMyInitialView(true);
};
And in the SiteContainer
<SafeAreaView style={styles.siteContainer}>
// here I don't know a way to display a component in react-native, so
// you need to display the component MyInitialView if the
// toViewMyInitialView is true and when toViewMyInitialView id false it
// display MyDynamicViewArea
{toViewMyInitialView && <MyInitialView/>}
{!toViewMyInitialView && <MyDynamicViewArea/>}
<TouchableOpacity onPress={() => {handleChangeMyView()}}>
<View>
<FontAwesome name="quote-left"></FontAwesome>
</View>
</TouchableOpacity>
</SafeAreaView>
I am new to react native and have a problem figuring out how to navigate from one class to another one with passing parameters and would appreciate your help.
All I want to do is:
ClassA should have a checkbox with state handling and a flatlist containing CustomButton
Navigate from ClassA to TargetScreen by clicking CustomButton
Pass parameter "element" to TargetScreen
Show content of parameter passed in TargetScreen
The error message I get:
Error: Invalid hook call. Hooks can only be called inside of the body
of a function component. This could happen for one of the following
reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app See https://reactjs.org/warnings/invalid-hook-call-warning.html for tips about how to debug and
fix this problem.
ClassA:
import React, { Component, useState } from 'react';
import { useNavigation } from '#react-navigation/native';
import { CustomButton} from './CustomButton.js';
import { CheckBox, SafeAreaView, FlatList} from 'react-native';
class ClassA extends React.Component {
render() {
const [ASelected, setA] = useState(false);
const NavigateWithParams = () => {
navigation = useNavigation();
this.props.navigation.navigate('TargetScreen', { element: 'elementname' })
}
const renderItemCustom= ({ item }) => (
<CustomButton onPress={() => navigateWithParams()} />
);
}
return (
<CustomConst/>
<CheckBox value={ASelected}
onValueChange={{setA}} />
<SafeAreaView>
<FlatList
data={data}
renderItem={renderItemCustom}
keyExtractor={(item) => item.element}
/>
</SafeAreaView>
);
}
export default ClassA;
TargetScreen:
class TargetScreen extends React.Component {
render() {
const { navigation } = this.props;
return (
<Text> {JSON.stringify(navigation.getParam('element'))} </Text>
);
}
}
export default TargetScreen;
+++++++++++++++++++++++++
Update:
As of now the code looks like this:
class ClassA extends React.Component {
NavigateWithParams = (element) => {
this.props.navigation.navigate('TargetScreen', { element: 'elementname' })
}
renderItemCustom = ({ item }) => (
<CustomButton element={item.title} onPress={() => this.NavigateWithParams(item.element)} />
);
render() {
return (
<SafeAreaView>
<FlatList
data={data}
renderItem={this.renderItemCustom}
keyExtractor={(item) => item.id}
/>
</SafeAreaView>
);
}
}
export default ClassA;
And I am now getting this issue:
TypeError: Cannot read property 'navigate' of undefined
+++++++++++++++++++++++++
Update2
Routing:
function ClassA({ navigation }) {
return (
<ClassAScreen/>
);
function Target({ navigation }) {
return (
<TargetScreen/>
);
//navigation stacks
const SessionStack = createStackNavigator();
function SessionStackScreen({ navigation }) {
return (
<SessionStack.Navigator>
<SessionStack.Screen
name="ClassA"
component={ClassA}
options={{ tabBarLabel: 'ClassA!', headerShown: false }}
/>
<SessionStack.Screen
name="Target"
component={Target}
options={{ tabBarLabel: 'works!' }}
/>
</SessionStack.Navigator>
)
}
Logging gives me this:
renderItemCustom = ({ item }) => (
<CustomButton element={item.title} onPress={() => console.log(this.props)} />
);
+++++++++++++++++
Update:
Solution can be found here:
Navigation with parameters from custom element in Flatlist in React Native: Empty parameters
You cant use hooks inside a class component so remove the line which has the hook
and change like below
const NavigateWithParams = element => {
this.props.navigation.navigate('TargetScreen', { element: element })
}
const renderItemCustom= ({ item }) => (
<CustomButton onPress={() => this.navigateWithParams(item.element)} />
);
And parameter are passed using the route prop
class TargetScreen extends React.Component {
render() {
const { route} = this.props;
return (
<Text> {JSON.stringify(route.params.element)} </Text>
);
}
}
Also for the checkbox instead of using the useState hook, use this.state.
You can’t use Hooks inside a class component
https://reactjs.org/docs/hooks-faq.html#should-i-use-hooks-classes-or-a-mix-of-both
UPDATE:
Work variant, you can try here: https://snack.expo.io/#vasylnahuliak/stackoverflow-67862370
import 'react-native-gesture-handler';
import React from 'react';
import { Text, View, StyleSheet, Button, FlatList } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const DATA = [
{
id: 0,
title: 'first button',
element: 'something'
},
{
id: 1,
title: 'second button',
element: 'another something'
},
]
const HomeSceen = ({ route, navigation }) => {
return (
<View>
<Text>{JSON.stringify(route, null, 2)}</Text>
<Button
title="Navigate to ProfileScreen"
onPress={() => {
navigation.navigate('ProfileScreen');
}}
/>
</View>
);
};
const ProfileScreen = ({ route, navigation }) => {
const NavigateWithParams = (element) => {
navigation.navigate('HomeSceen', { element });
};
const renderItemCustom = ({ item }) => (
<Button title={item.title} onPress={() => NavigateWithParams(item.element)} />
);
return (
<View>
<Text>{JSON.stringify(route, null, 2)}</Text>
<FlatList
data={DATA}
renderItem={renderItemCustom}
keyExtractor={(item) => item.id}
/>
<Button
title="Navigate to HomeSceen"
color="tomato"
onPress={() => {
navigation.navigate('HomeSceen');
}}
/>
</View>
);
};
const SessionStack = createStackNavigator();
const App = () => {
return (
<NavigationContainer>
<SessionStack.Navigator>
<SessionStack.Screen name="HomeSceen" component={HomeSceen} />
<SessionStack.Screen name="ProfileScreen" component={ProfileScreen} />
</SessionStack.Navigator>
</NavigationContainer>
);
};
export default App;
I am currently creating an onboarding screen which is just a few components navigating linear to the next component on a button click.
However I’ve seen I could use a flatlist to style this better. Is it possible to pass components to a flatlist as the data prop?
import React from 'react';
import { SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar } from 'react-native';
import DateOfBirth, Name, ProfilePicture from ‘./components’
const DATA = [
DateOfBirth, Name, ProfilePicture
];
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
/>
</SafeAreaView>
);
}
Would this be possible for example? I know there is a renderedItems prop which seems to do something similar but seems to match the data to the item which isn’t what I really want. Is there anyway better?
Or if there is any better libraries for onboarding options in react native that would be great. Most of what I see is similar to a flatlist and adds just an array with text rather than inputs etc
import React from 'react';
import {View,Text,StyleSheet,FlatList} from 'react-native';
const Demo = () => {
let ary = [
{
id:1,
name:'jahnavi',
},
{
id:2,
name:'yash',
},
{
id:3,
name:'aniket',
}],
return (
<SafeAreaView style={styles.container}>
<FlatList
keyExtractor={item => item.id}
data={ary}
renderItem={({item}) => (<Item title={item.name}/>
);
}
/>
</SafeAreaView>
);
};
export default Demo;
You also need to set the renderItem prop. Style the <Item /> component to meet your requirement.
const App = () => {
const renderItem = ({ item }) => (
<Item title={item.title} />
);
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
};
Don't understand why you're trying to do with your components.
To use Flatlist, you need to pass data and THEN use your components.
Learn more here https://reactnative.dev/docs/flatlist
Example
import React from 'react';
import { SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar } from 'react-native';
import DateOfBirth, Name, ProfilePicture from ‘./components’
const DATA = [
{
name: "Jhon Doe",
dateOfBirth: "01/01/1980",
profilePicture: "https://url.com/profile.jpg"
},
{
name: "Jane Doe",
dateOfBirth: "02/01/1980",
profilePicture: "https://url.com/profile2.jpg"
}
];
const App = () => {
function renderClient ({client}){
return(
<View key={client.index}>
<Name name={client.item.name} />
</View>
)
}
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
keyExtractor={(item, index) => index.toString()}
renderItem={renderClient}
/>
</SafeAreaView>
);
}
}
const DATA = [
<MyComponent />,
<MyOtherComponent />,
<Etc />,
<Etc />,
]
const ListItem = ({ item }) => {
return <View> {item} </View>
}
<View>
<FlatList
data={DATA}
keyExtractor={(item, index) => String(index)}
renderItem={ListItem}
/>
</View>
I have created a component called OrderGuideSelect and I am trying to render it in another area of our app. The problem is the OrderGuideSelect component is not rendering. When I set up breakpoints I am able to hit inside of the renderOrderGuideOptions function but it never makes it into the OrderGuideSelect.js file. I also tried putting 'export default' in front of the class declaration instead of the connection but it didn't make a difference. Does anyone know how to get the OrderGuideSelect component rendering properly?
Here is where I call the function that renders the OrderGuideSelect component:
<TouchableOpacity onPress={() => this.renderOrderGuideOptions()}>
<MBIcon name="ico-24-filter" size={30} style={styles.filterIcon}/>
</TouchableOpacity>
And here is the rendering function:
renderOrderGuideOptions = () => {
return (
<View>
<OrderGuideSelect />
</View>
)
}
Here is the OrderGuideSelect.js file:
import React, {Component} from 'react';
import {View, FlatList, ActivityIndicator, StyleSheet} from 'react-native';
import {connect} from 'react-redux';
import {fetchOrderGuides} from '../../actions/AppActions';
import {orderGuideSelected} from '../../actions/ProductAction';
import Header from '../../components/Header/Header';
import {createIconSetFromIcoMoon} from 'react-native-vector-icons';
import selection from '../../selection';
import OrderGuideOption from './OrderGuideOption';
const MBIcon = createIconSetFromIcoMoon(selection);
class OrderGuideSelect extends Component {
constructor(props) {
super(props);
}
componentWillMount() {
this.props.dispatch(fetchOrderGuides());
}
selectOrderGuide = id => {
this.props.dispatch(orderGuideSelected(id));
}
render() {
const {isLoading, orderGuides} = this.props.orderGuide;
return (
<View style={styles.wrapper}>
<Header />
<View style={styles.iconLine}>
<MBIcon name='ico-24-filter' style={styles.filterIcon} />
</View>
{isLoading &&
<ActivityIndicator
style={{alignSelf: 'center'}}
animating={true}
size='large'
/>
}
{!isLoading &&
<View style={styles.optionList}>
<FlatList
style={styles.optionList}
data={orderGuides}
keyExtractor={(item, index) => item.id.toString()}
renderItem={({item}) => <OrderGuideOption guideData={item} isSelected={item.id == this.props.selectedGuide.id} onSelected={this.selectOrderGuide} />}
/>
</View>
}
</View>
);
}
}
function mapStateToProps(state){
const {products, orderGuide} = state;
return {
selectedGuide: products.selectedOrderGuide,
orderGuide
}
}
export default connect(mapStateToProps)(OrderGuideSelect);
Also, I may be importing of the OrderGuideSelect component should be correct:
In your code calling this.renderOrderGuideOptions function on onPress event doesn't make sense, i.e. this.renderOrderGuideOptions returns the element but where to append it in DOM?
This should be achived using state in React. So you can set the state in onPress handler then use that state in render to show your OrderGuideOptions component.
So on onPress event bind the function handler:
<TouchableOpacity onPress={this.showOrderGuideOptions}>
<MBIcon name="ico-24-filter" size={30} style={styles.filterIcon}/>
</TouchableOpacity>
Now this showOrderGuideOptions will set the state named showOrderGuideFunction to true.
showOrderGuideOptions(){
this.setState({showOrderGuideFunction: true});
}
At last step use this showOrderGuideFunction state to render your component in the render function like this:
render() {
return (
<div>
...
{
this.state.showOrderGuideFunction &&
renderOrderGuideOptions()
}
</div>
)
}
You can do what you want probably holding a state property in your component and show your OrderGuideOptions according to this state property.
state = { showOrderGuideOptions: false };
renderOrderGuideOptions = () =>
this.setState( prevState => ( { showOrderGuideOptions: !prevState.showOrderGuideOptions }) );
render() {
return (
<View>
<TouchableOpacity onPress={this.renderOrderGuideOptions}>
<MBIcon name="ico-24-filter" size={30} style={styles.filterIcon}/>
</TouchableOpacity>
{ this.state.showOrderGuideOptions && <OrderGuideSelect /> }
</View>
)
}
I think you wanted to something similar to this
class RenderOrderGuideSelectComponent extends Component {
constructor(props) {
super(props);
this.state={
showOrderGuideSelect : false
};
}
renderOrderGuideOptions = () => {
this.setState({showOrderGuideSelect: true});
}
render() {
if(this.state.showOrderGuideSelect) {
return (
);
} else {
return (
this.renderOrderGuideOptions()}>
);
}
}
}
import React, { Component } from 'react';
import { AppRegistry, Text, View, TouchableOpacity } from 'react-native';
class Check extends Component {
constructor(props){
super(props);
this.pressed = true
}
_callme = () => {
if(!this.pressed){
return ( <View>
<TouchableOpacity onPress={this._callMe}>
Show me TextBox
</TouchableOpacity>
</View>
)
}
else{
return (
<View>
<TextInput />
</View>)
}
}
showText = () => {
return (
<TouchableOpacity on Press={this._callMe}>
<Text>Show me TextBox</Text>
</TouchableOpacity>
)
}
render() {
return(
<View>
{this.pressed ? this._callMe : this.showText}
</View>
)
}
}
AppRegistry.registerComponent('Check', () => Check);
I am Newbie into the ReactNative, what I want is when ever a user clicks on a button user should get a popup box for comment, but I don't know where I am doing wrong?
Since you want to render the returned value, you need to call the function with ()
{this.pressed ? this._callMe() : this.showText()}
Also showText function return component <TouchableOpacity on Press={this._callMe}> has a space between on Press change to onPress.