I am building an application using React Native, and I want to use data from Heroku api. But when I make an API call and consolog the data I can see the data, but when I try to map them, nothing is coming out of the DOM. Can anyone tell me what I am doing wrong? Thank you so much. Here below are my can and a screenshop.
App.jsx:
import react, { useEffect, useState } from "react";
import { FlatList, useWindowDimensions, View, Text } from "react-native";
import axios from "axios";
const App = () => {
const { height } = useWindowDimensions();
const [places, setPlaces] = useState({});
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
useEffect(() => {
axios
.post(
"https://where2playdk.herokuapp.com/nearest?lat=55.70232019168349&lon=12.561693791177802"
)
.then((response) => console.log(response.data))
.catch((error) => setIsError(error))
.finally(() => setIsLoading(false));
}, []);
return (
<View>
{places.map(({ name, distance }) => (
<View>
<Text>name</Text>
<Text>{name}</Text>
<Text>{distance}</Text>
</View>
))}
</View>
);
};
export default App;
you are not updating the state here, only consoling the data,
useEffect(() => {
axios
.post(
"https://where2playdk.herokuapp.com/nearest?lat=55.70232019168349&lon=12.561693791177802"
)
.then((response) => setPlaces(response.data)) // here is the
//mistake
.catch((error) => setIsError(error))
.finally(() => setIsLoading(false));
}, []);
I've haven't worked with React Native but if it's the same as regular React, then the first problem I see is that each element inside your map should have a key:
{places.map(({ name, distance }) => (
<View key={name}>
{/* ... */}
</View>
))}
You also need to handle the loading state. Because when App first runs, places is undefined, so you are calling undefined.map which will probably throw an error. An early return would suffice.
if (!places) return <Text>Loading...</Text>
And I also don't see the setPlaces() being called, I assume you replaced it with the console log?
Related
I want to make a component, which should have an input and button. The button should do some kind of work, I want it to show the information that I need to receive with fetch. In this case my code is not working, it shows a lot of [objects], however I want it to show the information from the base. if you can please help... : )
import React, { useState } from 'react';
const App = () => {
const [User, setUser] = useState({num: ""})
const [Open, setOpen] = useState(false)
const users = () => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((json) => {
document.write(json);
});
};
return( <>
<input name="Num" />
<button onClick={users}> Click Me for users </button>
</>)
}
export default App ```
You should almost never use document.write
Following is one of they ways you can solve your problem
import React, { useState } from "react";
const App = () => {
const [User, setUser] = useState({ num: "" });
const [Open, setOpen] = useState(false);
const [users, setUsers] = useState([]);
const fetchAndSetUsers = () => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((users) => {
setUsers(users);
});
};
return (
<>
<input name="Num" />
<button onClick={fetchAndSetUsers}> Click Me for users </button>
{users.map((user) => {
return <div>{user.name}</div>;
})}
</>
);
};
export default App;
Change the line of
document.write
to
setUsers(json)
You shouldn't manipulate UI directly in React using DOM methods since React uses Virtual DOM concept to update UI
document.write receive html element as parameter not a json object, if you just want to check if the fetch work you can do JSON.stringigy(json)
PS: sorry for my poor english
I'm trying to show data from an API call. The structure of the application looks like
MainComponent -> RefreshButton (this will fetch the data)
MainComponent -> ShowData (this will show the data that is being fetched)
MainComponent has a state userData that will store the response that was received from the API. Now the issue is, whenever I'm clicking the button, it is getting into an infinite loop of rendering and calls the API infinite times.
This is what the error shows:
Here is my MainComponent -
import React, { useEffect, useState } from "react";
import RefreshButton from "./RefreshButton";
import ShowData from "./ShowData";
const MainComponent = () => {
const [userData, setUserData] = useState();
useEffect(() => {
console.log(userData);
}, [userData]);
return (
<div>
<p style={{ textAlign: "center" }}>Main Component</p>
<RefreshButton setUserData={setUserData} />
{userData && <ShowData userData={userData} />}
</div>
);
};
export default MainComponent;
Here is my RefreshButton component -
import React from "react";
import axios from "axios";
const RefreshButton = ({ setUserData }) => {
const getData = () => {
axios
.get(`https://jsonplaceholder.typicode.com/todos`)
.then((response) => {
if (response.status === 200) setUserData(response.data);
})
.catch((err) => {
console.log(err);
});
};
return (
<div className="button-container">
<button className="fetch-data-button" onClick={() => getData()}>
Fetch new data
</button>
</div>
);
};
export default RefreshButton;
And here is my ShowData component -
import React from "react";
const ShowData = ({ userData }) => {
console.log("Here", userData);
return (
<>
{userData.map((info, idx) => (
<div className="user-data" key={idx}>
{info}
</div>
))}
</>
);
};
export default ShowData;
PS - I'm new to React and couldn't find a potential solution on this, there are several tutorials on how to fetch data from API calls and show it, but I wanted to know what I'm doing wrong here. Thanks in advance!
You might have misunderstood with the infinite loop error
It's actually a render error as being shown here:
To fix your render error, simply put an actual string variable in the {}
Because the response was an array of this object, so you can't simply render the whole object but need to pick an actual string variable inside:
[{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}],
Change to something like this:
const ShowData = ({ userData }) => {
console.log("Here", userData);
return (
<>
{userData.map((info, idx) => (
<div className="user-data" key={idx}>
{info.title} // <-- Put a title here.
</div>
))}
</>
);
};
Remove
useEffect(() => {
console.log(userData);
},[userData])
This will reevaluate component whenever user data changes, which Leeds to call showData infinitely
I m trying to add pull to refresh to fetch my data from my api but it is not working and i can'y find the problem within the code:
const[refresh,setRefresh]=useState(true)
const onRefresh=()=>{
try{
axios
.get('http://192.168.1.17:8000/File/')
.then((response)=> {
setFile(response.data);
setFilteredFile(response.data)
setEmpty(false)
setRefresh(false);
})}
catch(error){console.log(error)
}
}
useEffect(()=>{
onRefresh()
},[])
<FlatList style={DocumentStyle.flatstyle}
keyExtractor={(item)=>item['id']}
data={filteredfile}
renderItem={renderItem}
onRefresh={()=>onRefresh()}
refreshing={refresh}
/>
never mind me everyone, i haven't set my refresh back to true after the useEffect set it to false
The error is due to not importing useState, but you also need to import useEffect. I also dont see where some of the props your passing to FlatList are being used. But here's a working sample:
import {useState, useEffect} from 'react';
const FlatList = ({file, refreshing, onRefresh}) => {
return (
<div>
<p>{file}</p>
<button onClick={() => onRefresh(2)}>Load another todo</button>
</div>
)
}
export default function App() {
const [refresh, setRefresh] = useState(true);
const [file, setFile] = useState('');
useEffect(() => onRefresh(), []);
const onRefresh = (id=1) => {
try {
fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
.then(response => response.json())
.then(json => {
console.log(json)
setFile(JSON.stringify(json))
setRefresh(false);
})
}
catch(error) {
console.log(error);
}
}
return <FlatList file={file} refreshing={refresh} onRefresh={onRefresh} />
}
I am trying to build a basic web app where a user can search for subreddits using the Reddit API.
However, while I can console.log the data I need from the API I cannot seem to figure out how to display it.
import React, { useState, useEffect } from "react";
import Amplify, { API, graphqlOperation } from "aws-amplify";
import aws_exports from "./aws-exports";
import { withAuthenticator, AmplifySignOut } from '#aws-amplify/ui-react';
import awsconfig from "./aws-exports";
import './App.css'
import axios from 'axios'
import CharacterGrid from './components/CharacterGrid'
import SearchBar from './components/SearchBar'
Amplify.configure(awsconfig);
const App = () => {
const [items, setItems] = useState([])
const [isLoading, setIsLoading] = useState(true)
const [query, setQuery] = useState('')
useEffect(() => {
const fetchItems = async () => {
setIsLoading(true)
const result = await axios(
`https://www.reddit.com/subreddits/search.json?q=${query}`
)
setItems(result.data)
setIsLoading(false)
}
fetchItems()
}, [query])
return (
<div className='container'>
<AmplifySignOut/>
<SearchBar style={{ marginTop: "6%" }} getQuery={(q) => setQuery(q)} />
<CharacterGrid isLoading={isLoading} items={items} />
</div>
)
}
export default withAuthenticator(App)
The child component CharacterGrid looks like this:
import React from 'react'
import CharacterItem from './CharacterItem'
const CharacterGrid = ({items, isLoading}) => {
return
isLoading
? (<h1>Loading ...</h1>)
: (
<section className='cards'>
<p>{items.data}</p> //this does not work
<p>{items.children}</p> //this does not work either
</section>
)
}
export default CharacterGrid
All I want to do is show the names of the subreddits that are returned from the API for the query string the user enters. Where am I going wrong? I have also tried converting to JSON, and mapping through the responses using .map() but I keep getting errors no matter what I try. Where am I going wrong?
However, while I can console.log the data I need from the API I cannot seem to figure out how to display it.
Because Reddit API returns an array of subreddits you should use map() function to iterate over the array and convert each item into React element.
items.map(i => (
<li key={i.data.display_name_prefixed}>
{i.data.display_name}
</li>
))
All I want to do is show the names of the subreddits that are returned from the API for the query string the user enters.
You need to inspect the data schema yourself and scrape the response properly.
Here is working example:
const { useState, useEffect } = React;
const App = () => {
const [items, setItems] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [query, setQuery] = useState("");
useEffect(() => {
setIsLoading(true);
if (query.length >= 3) {
axios(`https://www.reddit.com/subreddits/search.json?q=${query}`)
.then(response => setItems(response.data.data.children))
.catch(error => console.log("Error", error));
}
setIsLoading(false);
}, [query]);
return (
<div>
<input type="text" value={query} onChange={e => setQuery(e.target.value)} />
<CharacterGrid items={items} isLoading={isLoading} />
</div>
);
}
const CharacterGrid = ({ items, isLoading }) => {
return isLoading ? (
<h1>Loading ...</h1>
) : (
<ul>
{items.map(i => (
<li key={i.data.display_name_prefixed}>
{i.data.display_name} ({i.data.display_name_prefixed})
</li>
))}
</ul>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
<div id="root"></div>
In order to loop through the elements and e.g: print the title, you could do the following.
items.data.children.map(child => <p> child.data.title </p>)
According to the response provided by reddit,
reddit response
I get a warning in my FlatList when using the useEffect hook to fetch data.
This is the complete component to reproduce the issue:
import React, { useState, useEffect } from "react";
import {
Text,
View,
FlatList,
ActivityIndicator,
SafeAreaView,
Button
} from "react-native";
const Test = props => {
const [people, setPeople] = useState([]);
const [loading, setLoading] = useState(false);
const [page, setPage] = useState(1);
useEffect(() => {
setLoading(true);
fetch(`http://jsonplaceholder.typicode.com/photos?_start=${page}&_limit=20`)
.then(res => res.json())
.then(res => {
//console.log(res);
setPeople(people => [...people, ...res]);
setLoading(false);
});
}, [page]);
const loadMore = () => {
setPage(page + 20);
};
return (
<SafeAreaView style={{ flex: 1 }}>
<FlatList
data={people}
keyExtractor={item => item.id}
renderItem={({ item }) => (
<View>
<Text>{item.id}</Text>
<Text>{item.title}</Text>
</View>
)}
ListFooterComponent={
loading ? (
<ActivityIndicator />
) : (
<Button title="Load More" onPress={loadMore} />
)
}
/>
</SafeAreaView>
);
};
export default Test;
This is the warning I'm getting
VirtualizedList: You have a large list that is slow to update - make sure your renderItem function renders components that follow React performance best practices like PureComponent, shouldComponentUpdate, etc. Object {
"contentLength": 4418,
"dt": 705,
"prevDt": 669,
}
It basically tells me to use PureComponent or shouldComponentUpdate, though, but AFAIK both do not work with either a functional component or the useEffect hook, do they?
Although I did not notice a (huge) performance drop, I'm still wondering if there's a workaround to fix this issue. Any help would be appreciated. Thank you very much.
Edit: Using a PureComponent does not fix the issue:
Created PureComponentTest.js
import React from "react";
import { Text, View } from "react-native";
const PureComponentTest = props => {
return (
<View>
<Text>{props.id}</Text>
<Text>{props.title}</Text>
</View>
);
};
export default PureComponentTest;
And in my Component I updated renderItem={renderItems}:
const renderItems = itemData => {
return (
<PureComponentTest
id={itemData.item.id}
title={itemData.item.title}
/>
);
};
I really don’t see anything wrong with your component. It’s a very simple pure component. It may simply because the fetched data is too big. Try reduce the number of pages fetched each time. say 5 or 10 pages
maybe the warning is for fetch into useEffect, so review the next documentation:
Some rules to keep in mind about the useEffect hook:
You cannot call a hook within a conditional; Hooks must be called in
the exact same order. Putting the useEffect inside of a conditional
could break that cycle; The function you pass the hook cannot be an
async function, because async functions implicitly return promises,
and a useEffect function either returns nothing or a cleanup function.
Consider use it:
fetch(`http://jsonplaceholder.typicode.com/photos?_start=${page}&_limit=20`)
.then(res => res.json())
.then(res => {
//console.log(res);
setPeople(people => [...people, ...res]);
})
.catch(error=> console.error(error))
.finally(() => setLoading(false));