React Native JSON issue with YouTube Data v3 API call - react-native

I have a request pulling in from YouTube, to create a list of videos I want to display in a flatlist. I use the same approach across the application (calling WordPress, etc...), but when Im trying to achieve the same with the YouTube API (I've got the key setup etc..), it throws an error;
const Watch = ({typeOfProfile}) => {
const [isLoading, setLoading] = useState(true);
const [data, setData] = useState([]);
let x = {foo: 11, bar: 42};
function playertype(val) {
return 'https://www.googleapis.com/youtube/v3/searchpart=snippet&channelId=UCa_6KiOjxm6dEC_mMRP5lGA&maxResults=20&order=date&type=video&key=xxxxx';
}
useEffect(() => {
fetch(playertype(typeOfProfile))
.then((response) => response.json())
.then((json) => {
x = setData(json)
})
.catch((error) => console.error(error))
.finally(() => setLoading(false));
}, []);
const result = Object.keys(x).map(key => ({[key]: x[key]}));
return (
<View style={styles.body}>
<View style={styles.topscroll}>
{isLoading ? <ActivityIndicator/> : (
<FlatList
data={result}
horizontal={true}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<View>
<Text>
{x.val}
</Text>
</View>
)}
/>
)}
</View>
</View>
);
};
Someone mentioned it could be an object being returned instead of an array, seems odd the json structure is the same as other requests I use this approach for.

I discovered that I had to add brackets on the data property of the FlatList. So instead of
data={data}
I had to change it too;
data={[data]}
Code now;
<FlatList
data={[data]}
horizontal={true}
keyExtractor={({ id }, index) => id}
renderItem={({ item, index }) => (
<View style={styles.container}>
<Image style={styles.imgyoutubeprev} source={{ uri: chkValue(item.items[0].snippet.thumbnails.high.url) }} />
</View>
)}
/>

Related

Why my virtualized list does not re-render when the data passed as prop actualizes?

I am having a problem that I can't solve by my own. I am making an app for making lists in React Native, and in my main screen, that shows the session initiated by the user, I have to render all the lists that he had saved previously. Here is the code of my session component.
export default function Session({navigation,route}){
const {user} = useContext(myContext)
const [modalVisible, setModalVisible] = useState(false)
const [lists, setLists] = useState(route.params.lists)
let keyListCounter = 0
const handleButton = async () => {
await AsyncStorage.removeItem("token")
navigation.navigate("Login")
}
const updateList = (title,newElement) => {
axios.put(`http://${REACT_APP_BACK_URI}/api/lists/add-list-element`, {nickname: user,title,element: newElement})
.then(res => {
if (res.status == 200) {
setLists(res.data.userLists)
}
})
.catch(err => console.log(err))
}
useEffect(() => {
navigation.setOptions({
title: user,
headerTitleAlign: "left",
headerRight: () => (
<TouchableWithoutFeedback onPress={() => handleButton()}>
<Text style={styles.logoutText}>Logout</Text>
</TouchableWithoutFeedback>
)
})
},[navigation,user])
return (
<View style={styles.mainContainerView}>
<ScrollView style={styles.mainContainerScrollView}>
<View style={styles.textListContainer}>
<Text style={styles.listsText}>LISTAS ACTIVAS: </Text>
<Text style={styles.numberListsText}>{lists.length}</Text>
</View>
{lists.map(elem => <List key={keyListCounter++} list={elem} updateList={updateList}/>)}
</ScrollView>
<Pressable style={styles.newListPressable} onPressIn={() => setModalVisible(true)}>
<Text style={styles.newListText}>+</Text>
</Pressable>
<View style={styles.centeredView}>
<Modal
visible={modalVisible}
animationType="slide"
transparent={true}
>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text>MODAL</Text>
</View>
</View>
</Modal>
</View>
</View>
)
}
My question is why after I actualize the state of "lists", whose elements are passed as props to the List component, the virtualized list that I have in the List component does not re-renderizes automaticaly.
Here I show also the code of the List component.
export default function List({list,updateList}){
const {elements, title} = list
let elementId = 0
const virtualizedList = useRef()
const [showVirtualizedList, setShowVirtualizedList] = useState("none")
const [showDownArrow, setShowDownArrow] = useState(true)
const [showUpArrow, setShowUpArrow] = useState(false)
let [newElementArray, setNewElementArray] = useState([])
let [listElements, setListElements] = useState(elements)
const getItem = (item) => ({
id: elementId++,
title: item
});
//List Pressable Events
const handlePressIn = () => {
if (showVirtualizedList == "none") setShowVirtualizedList("flex")
else setShowVirtualizedList("none")
setShowDownArrow(!showDownArrow)
setShowUpArrow(!showUpArrow)
}
//New element Pressable Events
const handleNewElement = () => {
setNewElementArray([...newElementArray,uuid.v4()])
}
//NewListItem TouchableWithoutFeedback Events
const deleteElementInput = newItemID => {
const elementsArray = newElementArray.filter(elem => elem != newItemID)
setNewElementArray(elementsArray)
}
const addListElement = (newElement,newItemID) => {
updateList(title,newElement)
deleteElementInput(newItemID)
}
useEffect(() => {
virtualizedList.current.setNativeProps({display: showVirtualizedList})
LogBox.ignoreLogs(['VirtualizedLists should never be nested']);
},[showVirtualizedList, virtualizedList])
return (
<ScrollView style={styles.mainContainer}>
<Pressable
style={styles.listElement}
onPressIn={() => handlePressIn()}
>
<View style={styles.titleContainer}>
<Text style={styles.listElementText}>{title} </Text>
<Text style={styles.listElementQuantity}>({listElements.length})</Text>
</View>
<View>
<DownArrow show={showDownArrow}/>
<UpArrow show={showUpArrow}/>
</View>
</Pressable>
<View>
<VirtualizedList
data={listElements}
initialNumToRender={10}
getItemCount={() => listElements.length}
renderItem={({item}) => <ListItem item={item}/>}
getItem={() => getItem(listElements[elementId])}
ref={virtualizedList}
/>
</View>
{newElementArray.length > 0 ? newElementArray.map(elem => {
return (
<NewListItem
key={elem}
id={elem}
newElementArray={newElementArray}
deleteElementInput={deleteElementInput}
addListElement={addListElement}
/>
)
}) : ""
}
<Pressable style={styles.newElementPressable} onPressIn={() => handleNewElement()}>
<Text style={styles.newElementText}>+</Text>
</Pressable>
</ScrollView>
)
}
UPDATE: I solve the problem using a FlatList instead of a VirtualizedList. For some reason the FlatList re-renders when the Item is updated and the VirtualizedList no. I don't know why.....

how do I update useState immediately?

I'm trying to add and remove items from my movies favlist but I am unable to render things immediately with useState. I also trying to update favoritesFilm in UseEffect but my page crashed for continuing re-render.
This is my fav component:
export default function FavouriteBox() {
const navigation = useNavigation<NavigationProps>()
const [favoritesFilm, setFavorite] = useState<Movie[]>([])
const [isLoadingFav, setIsLoadingFav] = useState(true)
useEffect(() => {
getFav()
}, [])
useEffect(() => {
console.log(favoritesFilm)
}, [favoritesFilm])
async function removeMovie() {
const removed = StorageResources.storageRemove('favmovies')
setFavorite(favoritesFilm)
}
async function getFav() {
const favoriteMovies = await StorageResources.storageGet('favmovies')
setFavorite(favoriteMovies)
setIsLoadingFav(false)
}
const renderItemFav = ({ item }: any) => (
<FavMovie name={item.name} title={item.title} poster_path={item.poster_path} id={item.id} />
)
const FavMovie = ({ title, poster_path, name, id }: any) => (
<View style={styles.wrap}>
<Image
style={styles.image}
source={{
uri: `https://image.tmdb.org/t/p/w500/${poster_path}`,
}}
/>
{title && <Text style={styles.fav}>{title}</Text>}
{!title && <Text style={styles.fav}>{name}</Text>}
<MaterialCommunityIcons onPress={() => removeMovie()} name="bookmark-minus-outline" style={styles.book} />
</View>
)
return (
<View style={styles.container}>
<Text style={styles.title}>Preferiti</Text>
{isLoadingFav && <LoaderBox />}
{!isLoadingFav && (
<FlatList
data={favoritesFilm}
keyExtractor={(item) => item.id}
renderItem={renderItemFav}
horizontal
></FlatList>
)}
</View>
)
}
In my home component I use this function to add to fav:
const addToFavorites = async (item: Movie) => {
if (favorites.includes(item)) return null
StorageResources.storageSave('favmovies', [...favorites, item])
setFavorites([...favorites, item])
}
I would like to understand why it doesn't work and why every time I want to show movies in the favmovies component I have to refresh. (I used AsyncStorage for getItem and removeItem)

Retrieving data from a Text Input and sending it to an api

I'm working on an application in React Native to experiment with this and I made a bee in Django to retrieve data and send data.
For example, how can I send my data from an input text via a post to django?
For example for get I use something like this
const [todos, setTodos] = useState({});
const todoData = () => {
axios.get('http://192.168.1.5:8000/app/todo-data/')
.then(response => setTodos(response.data))
.catch(error => {
console.error('There was an error!', error);
});
};
React.useEffect(() => {
todoData();
}, []);
My question is how could I put in a "state" what data I want to send?
In Django I want to send this
{
"item":"how to make"
}
I want to send an item with a text as a post
And this is my TextInput
<View style={styles.container}>
<Header />
<View style={styles.header}>
<View style={styles.content}>
<View style={styles.list}>
<TextInput style={styles.textInput} editable maxLength={40}/>
<FlatList data={todos} renderItem={({ item }) => (
<TodoItem item={item} pressHandler={pressHandler} />
)}>
</FlatList>
</View>
</View>
</View>
</View>
To get input value to state you can use TextInput onChange callback.
https://reactnative.dev/docs/textinput#onchange
const [inputValue, setInputValue] = useState(null)
<TextInput
value={inputValue}
onChange={(val) => setInputValue(val)}
/>
Then you can include inputValue in POST request.

React Native - Navigate to detail screen by clicking on item in flatList?

I'm rendering names out of an API by using flatList. I'm then trying to make each item clickable and display more information about that person they clicked on, and i'm not sure how to go about things. Some posts i've read here on Stackoverflow that has links to examples are now dead and not useable.
I'm using DrawerNavigation and i will try my best to include the code needed, i have all my Screens in the app.js file.
App.js
export default function App() {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home" drawerPosition="right">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Players" component={PlayersScreen} />
</Drawer.Navigator>
</NavigationContainer>
);
};
Each Screen has its own function bellow this, here is the PlayerScreen example which is the one containing the list rendered by flatList.
function PlayersScreen( { navigation } ) {
const [isLoading, setLoading] = useState(true);
const [data, setData] = useState([]);
useEffect(() => {
fetch('http://***.**.***.**:3000/players',
{ credentials: "same-origin",
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
},
)
.then((response) => response.json())
.then((json) => setData(json))
.catch((error) => console.error(error))
.finally(() => setLoading(false));
}, []);
return (
<View style={{marginTop: StatusBar.currentHeight}}>
<TouchableOpacity onPress={() => navigation.dispatch(DrawerActions.toggleDrawer()) }>
<Text>+</Text>
</TouchableOpacity>
<FlatList
data={data}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<Text>{item.Name}</Text>
)}
/>
</View>
);
---EDIT----
My flatlist currently look like this
<FlatList
data={data}
keyExtractor={item => item.Name}
renderItem={({ item }) => (
<Text style={{fontSize: 32, color: 'white'}} onPress={() => alert("clicked")}>{item.Name}</Text>
)}
/>
So now how do i handle that onPress to navigate to a component that will display more information about the name selected?
Any help is appreciated, cheers,
N
First of all, it looks like you don't really want to navigate to the detail screen, but rather unfold a detail component which is residing in the same screen as the flatlist.
If you really want to navigate to the detail screen, you'd have to pass a function with a call tonavigation.navigate to every item inside the renderItem property.
Like this:
<FlatList
data={data}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => {
navigation.navigate('ItemDetail', {data: item}
}
)}>
<Text>
+
</Text>
</TouchableOpacity>
/>
If you want to pass a component, you'd have to do something like this:
<FlatList
data={data}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<ItemDetail item={item}/>
)}
/>
and then handle the click on "+" inside your new ItemDetail component. Of cause you don't have to create a new component, you also can define all the markup inline, but it is cleaner and reusable if you use a new component.

i want to show a flat list data but not show some data especially image

I use this to collect data from my server
getPopularProduct = async () => {
const url = `https://swissmade.direct/wp-json/swissmade/home/popular`;
fetch(url)
.then(response => response.json())
.then((responseJson) => {
console.log(responseJson.products.thumbnail, "details")
if(responseJson.error == false){
this.setState({
dataSourcePopularProduct: responseJson.products,
//isLoading: false,
})
}
})
.catch((error) => {
console.log(error)
})
}
this the blank space imag and this is the flat list and render item
renderPopularProduct = ({ item }) => {
const entities = new Entities();
var id = item.pid;
var img = { 'uri': item.thumbnail };
return (
<TouchableOpacity onPress={() => this.props.navigation.navigate('ProductDetails', { id })}>
<View style={styles.GalleryBox}>
<View style={styles.GalleryImg} onPress={() => this.props.navigation.navigate("ProductDetails")}>
<Image source={img} style={styles.SingelImg} largeHeap="true"/>
</View>
<View style={styles.GalleryText}>
<Text style={styles.userNmae}>{item.title}</Text>
</View>
<View style={styles.amount}>
<Text style={styles.userNmae}>{entities.decode(item.currency)} {item.price}</Text>
</View>
</View>
</TouchableOpacity>
)
}
<FlatList
data={this.state.dataSourcePopularProduct}
renderItem={this.renderPopularProduct}
keyExtractor={(item, index) => index}
horizontal={true}
showsHorizontalScrollIndicator={false}
/>
and stylesheet
SingelImg: {
width: '150%',
height: '120%',
//resizeMode: 'cover',
marginLeft: -25
},
And this way I use flat list but when it shows some data are missing especially image. but my API returns every right data.