why not show text when calling api in react native - javascript

when calling api returns only red background but not text
I expect the api to return a list of movies displayed on the app interface
but when i return the Items function directly inside the render function, it returns me the text, but when I call the function outside, it just doesn't return the text but just the background
import React, {useEffect, useState} from 'react';
import {ActivityIndicator, FlatList, Text, View} from 'react-native';
import Axios from 'axios';
export default App = () => {
const [isLoading, setLoading] = useState(true);
const [data, setData] = useState([]);
useEffect(() => {
Axios.get('https://reactnative.dev/movies.json')
.then(({data}) => {
setData(data.movies);
})
.catch(error => console.log('error', error))
.finally(() => setLoading(false));
}, []);
const Items = item => {
return (
<View>
<Text style={{flex: 1, backgroundColor: 'red', color: 'blue'}}>
{item.title}, {item.releaseYear}
</Text>
</View>
);
};
return (
<View style={{flex: 1, padding: 24}}>
{isLoading ? (
<ActivityIndicator />
) : (
<FlatList
data={data}
keyExtractor={(item, index) => {
return index.toString();
}}`enter code here`
renderItem={Items}
/>
)}
</View>
);
};

Change your Items component likewise :
const Items = ({item}) => {
return (
<View>
<Text style={{flex: 1, backgroundColor: 'red', color: 'blue'}}>
{item.title}, {item.releaseYear}
</Text>
</View>
);
};

Related

undefinded is not an object

Hello I'm facing with render error in my movie app during printing results for movie searching. Im working in React-Native 0.70.5. Here is some code for this activity
`
import React,{useState,useEffect} from 'react';
import axios from 'axios';
import { View, StyleSheet, Text, TextInput,ScrollView } from "react-native";
const Search = () => {
const apiurl="https://api.themoviedb.org/3/search/movie?api_key=XXX"
const [state,setState] = useState({
s: "Enter a movie",
results:[]
});
const search = () => {
axios(apiurl + "&query="+ state.s).then(({ data }) => {
let results = data.search;
console.log(data);
setState(prevState => {
return{...prevState, results: results }
})
})
}
return (
<View>
<TextInput
onChangeText={text => setState(prevState => {
return {...prevState, s:text}
})}
onSubmitEditing={search}
value={state.s}
/>
<ScrollView>
{state.results.map(result =>(
<View key={result.id}>
<Text>{result.title}</Text>
</View>
))}
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
center: {
flex: 1,
justifyContent: "center",
alignItems: "center",
textAlign: "center",
},
});
export default Search;
`
How to change the construction of this function to print movie titles corectly ?
This is just an example and not the best way to do it.
You need a success flag, something like this:
const [success,setSuccess] = useState(false);
const search = () => {
axios(apiurl + "&query="+ state.s).then(({ data }) => {
let results = data.results;
console.log(data);
setState(prevState => {
return{...prevState, results: results }
})
setSuccess(true);
})
}
<ScrollView>
{success && state.results.map(result =>(
<View key={result.id}>
<Text>{result.title}</Text>
</View>
))}
</ScrollView>
I am not sure but you can try this below ScrollView code...
<ScrollView>
{state.results.length>0 && (state.results.map((result) =>(
<View key={result.id}>
<Text>{result.title}</Text>
</View>
)))}
</ScrollView>
use optional chaining. Might be sometimes you don't get result.
<ScrollView>
{state?.results?.map(result =>(
<View key={result?.id}>
<Text>{result?.title}</Text>
</View>
))}
</ScrollView>
Let me know is it helpful or not

"Error: Invalid hook call. Hooks can only be called inside of the body of a function component.." in react native expo

TestScreen.js
export default function TestScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<AlcoResult/>
</View>
);
}
2.AlcoResult.js
import { StyleSheet, Text, View,TouchableOpacity } from 'react-native'
import React from 'react'
import AlcoTestButton from './AlcoTestButton'
const AlcoResult = () => {
return (
<View style={styles.container}>
<TouchableOpacity
onPress={()=>AlcoTestButton()}
style={styles.button}>
<Text style={{ color: "white"}}>pull data</Text>
</TouchableOpacity>
</View>
)
}
AlcoTestButton.js
import { StyleSheet, Text, View, ActivityIndicator, FlatList } from 'react-native'
import React, { useEffect, useState, Component } from 'react'
import { SafeAreaView } from 'react-navigation';
const url = "url";
const AlcoTestButton = () => {
const [isLoading,setLoading] = useState(true);
const [alcohol, setAlcohol] = useState([]);
const [temperature, setTemperature] = useState([]);
useEffect(() => {
fetch(url)
.then((response) => response.json())
.then((json) => {
setAlcohol(json.alcohol);
setTemperature(json.temperature);
})
.catch((error) =>alert(error))
.finally(setLoading(false));
})
return (
<SafeAreaView style={styles.container}>
{isLoading ? (<ActivityIndicator />) :(
<View>
<Text>Alcohol = {alcohol}</Text>
<Text>Temperature = {temperature}</Text>
</View>
)}
</SafeAreaView>
)
}
export default AlcoTestButton
So here is my code... I tried different solutions on several websites but still got the same error.
I'm new to react native, If possible could anyone point out what are my errors if any in the structure of the codes?
Thank you.
The problem is that you are calling a component and returning UI elements instead of a function when pressing the button, so i'd suggest something like this
(I'm unsure of the structure of your data, but this should put you on the right track at least)
const AlcoResult = () => {
const [isLoading,setLoading] = useState(false);
const [alcohol, setAlcohol] = useState();
const [temperature, setTemperature] = useState();
const fetchData= async ()=>{
setLoading(true)
fetch(url)
.then((response) => response.json())
.then((json) => {
setAlcohol(json.alcohol);
setTemperature(json.temperature);
})
.catch((error) =>{alert(error)})
.finally(()=>{setLoading(false)});
}
return (
<View style={styles.container}>
<TouchableOpacity
onPress={()=>fetchData()}
style={styles.button}>
<Text style={{ color: "white"}}>pull data</Text>
</TouchableOpacity>
{isLoading && (<ActivityIndicator />)}
{!isLoading && !!temperature && !!alcohol &&
<View>
<Text>Alcohol = {alcohol}</Text>
<Text>Temperature = {temperature}</Text>
</View>
}
</View>
)
}

Not sure how to map variable to show in app

Here's the function-
const setLoading = (value) => {
const messages = dashboards.data.message.filter((item) => {
const title = item.dashboardTitle || item.dashboardName;
return title.toLowerCase().startsWith(value.toLowerCase());
});
setFiltered(messages);
console.log(filtered);
};
I want to display the variable 'messages' separately in my app, how would I do that? 'messages' variable needs to be displayed within the default react native 'Text' component. I have written down 'messages' below within Text component but currently it's not displaying anything (since it is within function) -
import React, { useState, useEffect, useReducer } from 'react';
import { View, Text, StyleSheet, FlatList, ActivityIndicator, Keyboard} 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';
const AppHeader = ({
scene,
previous,
navigation,
searchIconVisible = false,
}) => {
const [dashboards, dispatchDashboards] = useReducer(apiStateReducer, {
data: [],
isLoading: true,
isError: false,
});
const [filtered, setFiltered] = useState([]);
const setLoading = (value) => {
const messages = dashboards.data.message.filter((item) => {
const title = item.dashboardTitle || item.dashboardName;
return title.toLowerCase().startsWith(value.toLowerCase());
});
setFiltered(messages);
console.log(filtered);
};
const dropShadowStyle = styles.dropShadow;
const toggleSearchVisibility = () => {
navigation.navigate('Search');
};
useEffect(() => {
CognitensorEndpoints.getDashboardList({
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>
<Text style={styles.headerText}>
{messages}
</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>
</>
);
};
If your messages variable is an array you can map it
{messages.map((message, key)=>(
<Text style={styles.headerText}>
{message.dashboardName}
</Text>
))}
Since your messages variable is stored in 'filtered' state, you can map it by doing this:
{filtered.map((item, index) => <Text key={index}>{item.dashboardName}<Text>)}

TypeError: undefined is not a function (near '...data.map...')

I updated my code thanks to your help.
When I launch the app with Expo, the opening works but 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.
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;
I would appreciate your comments please.
You could use ? (optional chaining) to confirm data doesnt yield to undefined before mapping.
data?.map((data, index) => {return <>....</>}
You need to return from data.map function to render the array items
return isLoading ? (
<ActivityIndicator />
) : (
<>
{data?.map((data, index) => {
return <View key ={index}>
<Text> {data.products_name_fr} </Text>
<Text> {data.brands} </Text>
<Text> {data.image_url} </Text>
<View style={styles.scan}>
<MaterialCommunityIcons
name="barcode-scan"
size={40}
color="black"
onPress={() => {
navigation.navigate("CameraScreen");
}}
/>
</View>
</View>;
})}
</>
);
Or short-hand of return
return isLoading ? (
<ActivityIndicator />
) : (
<>
data?.map((data, index) => (
<View key ={index}>
<Text> {data.products_name_fr} </Text>
<Text> {data.brands} </Text>
<Text> {data.image_url} </Text>
<View style={styles.scan}>
<MaterialCommunityIcons
name="barcode-scan"
size={40}
color="black"
onPress={() => {
navigation.navigate("CameraScreen");
}}
/>
</View>
</View>;
))
</>
);
I changed my code like this but I have the same error. Besides, the part of code which begins from: const styles=Stylesheet.create seems to be not active
import React, { useState, useEffect } from "react";
import { StyleSheet, Text, View, 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";
import axios from "axios";
function ProductsScreen() {
const navigation = useNavigation();
const [data, setData] = useState([]);
const [isLoading, setisLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
const data = await AsyncStorage.getItem("userData");
setisLoading(false);
setData(data);
};
fetchData();
}, []);
return isLoading ? (
<ActivityIndicator />
) : (
<>
{data?.map((data, index) => {
return (
<>
key ={index}
<Text> {data.products_name_fr} </Text>
<Text> {data.brands} </Text>
<Text> {data.image_url} </Text>
<View style={styles.scan}>
<MaterialCommunityIcons
name="barcode-scan"
size={40}
color="black"
onPress={() => {
navigation.navigate("CameraScreen");
}}
/>
</View>
</>
);
})}
</>
);
const styles = StyleSheet.create({
products: {
alignItems: "center",
justifyContent: "center",
},
scan: {
marginLeft: 30,
position: "absolute",
bottom: 0,
right: 20,
marginBottom: 60,
marginRight: 30,
padding: 10,
borderRadius: 10,
backgroundColor: "#ff9234",
},
});
}
export default ProductsScreen;
I changed a little bit my code and I got another type of error : Invariant violation: Text strings must be rendered within a component. I will really appreciate your comments and support to fix this
return isLoading ? (
<ActivityIndicator />
) : (
<>
data?.map((data, index) => (
<>
<Text> {data.products_name_fr} </Text>
<Text> {data.brands} </Text>
<Text> {data.image_url} </Text>
<View style={styles.scan}>
<MaterialCommunityIcons
name="barcode-scan"
size={40}
color="black"
onPress={() => {
navigation.navigate("CameraScreen");
}}
/>
</View>
</>
))
</>
);
}
In the useEffect, set the data as array. Example
const = [data, setData] = useState([]); // do this in your state
setData([data]); //do this in your useEffet hook

Screen switching by press on button react native

I just started to learn React-native. In this app I have a two buttons in header, first 'Todo', second 'Tags'. I want to chang content by press on these buttons. I think I need to change state.for clarityWhat I mean, when i tap on the button Tags, below I get TagScreen component, exactly the same for the button Todo. How to connect these components so that they work correctly?
app.js
import React, { useState } from 'react'
import { StyleSheet, View, FlatList } from 'react-native'
import { Navbar } from './src/Navbar'
import { TagScreen } from './src/screens/TagScreen'
import { TodoScreen } from './src/screens/TodoScreen'
export default function App() {
const [todos, setTodos] = useState([])
const [tags, setTags] = useState([])
const [appId, setAppId] = useState([])
const addTodo = title => {
setTodos(prev => [
...prev,
{
id: Date.now().toString(),
title
}
])
}
const addTags = title => {
setTags(prev => [
...prev,
{
id: Date.now().toString(),
title
}
])
}
const removeTags = id => {
setTags(prev => prev.filter(tag => tag.id !== id))
}
const removeTodo = id => {
setTodos(prev => prev.filter(todo => todo.id !== id))
}
return (
<View>
<Navbar title='Todo App!' />
<View style={styles.container}>
<TagScreen addTags={addTags} tags={tags} removeTags={removeTags}/>
{/* <TodoScreen todos={todos} addTodo={addTodo} removeTodo={removeTodo} /> */}
{/* HERE MUST CHANGED COMPONENTS */}
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
paddingHorizontal: 30,
paddingVertical: 20
}
})
navbar.js
import React from 'react'
import { View, Text, StyleSheet, Button, TouchableOpacity } from 'react-native'
export const Navbar = ({ title }) => {
return (
<View style={styles.padding}>
<View style={styles.navbar}>
<TouchableOpacity
style={styles.button}
>
<Text>Todo</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
>
<Text>Tags</Text>
</TouchableOpacity>
<Text style={styles.text}>{title}</Text>
</View>
</View>
)
}
well you need to track the visiblity of what is visible in your state,
in your App component, do this;
const [showTodos, setShowTodos] = useState(false);
const makeTodosInvisible= () => setShowTodos(false);
const makeTodosVisible = () => setShowTodos(true);
return (
<View>
<Navbar onTodoPress={makeTodosVisible } onTagPress={makeTodosInvisible} title='Todo App!' />
<View style={styles.container}>
{showTodos
? <TodoScreen todos={todos} addTodo={addTodo} removeTodo={removeTodo} />
: <TagScreen addTags={addTags} tags={tags} removeTags={removeTags}/>
}
{/* <TodoScreen todos={todos} addTodo={addTodo} removeTodo={removeTodo} /> */}
{/* HERE MUST CHANGED COMPONENTS */}
</View>
</View>
)
and in your navbar.js do this
export const Navbar = ({ title, onTodoPress, onTagPress}) => {
return (
<View style={styles.padding}>
<View style={styles.navbar}>
<TouchableOpacity
style={styles.button}
onPreesed={onTodoPress} // will hide Tags and show Todos
>
<Text>Todo</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPreesed={onTagPress} // will show Tags and hide Todos
>
<Text>Tags</Text>
</TouchableOpacity>
<Text style={styles.text}>{title}</Text>
</View>
</View>
)
}

Categories

Resources