I am trying to display the name of each of the teams using the following API:https://www.balldontlie.io/api/v1/teams. I have the following code in my main app.js file:
const result = await Axios('https://www.balldontlie.io/api/v1/teams')
console.log(result.data)
console.log(result.data.data[0])
This is successfully able to fetch the data and the first console line is able to display all data in the console while the second line displays all the information about the first team in the data. In each of the teams data information, they have one attribute that is called 'name' and says the team name. I was wondering on how I will be able to call this. When I have the following code in another file it doesn't display anything on the screen:
{Object.keys(items).map(item => (
<h1 key={item}>{item.data}</h1>
))}
What should I change item.data to be able to properly display the names of all the teams? I could provide more code if needed, but I thought this code would probably do.
Don't use axios, now JS has a better alternative called fetch. wrap call on a async function. finally destructor the data object. and void installing more things on your node_modules.
What's here ?
Request endpoint using callApi function
Collect only data from all json scope when finish promise.
Loop over each name
const myComponent = () => {
const names = [];
const callApi = async () => {
await fetch('https://www.balldontlie.io/api/v1/teams')
.then(r => r.json())
.then(resp => { const { data } = resp; return data; })
.catch(e => { console.log(e.message); });
};
callApi();
return <>
{names && names.length > 0
? <span>{names.map(({ id, name }) => <h1 key={id}>{name}</h1>)}</span>
: <span>No rows </span>}
</>;
According to your second block of code, you are trying to access a "data" property of a string, since you are mapping an array of keys of the items.
Effectively:
const item_keys = Object.keys(items);
//if the items is an array, item_keys = ["0","1",...]
//if items is an object, item_keys = ["id","name",...]
const result = item_keys.map(item => (
<h1 key={item}>{item.data}</h1>
));
//either way, result is an array of <h1>undefined</h1>
//because item is a string
Assuming you defined items as const items = result.data.data (edited), you should be able to display names like this:
{items.map((item, index) => (
<h1 key={index}>{item.name}</h1>
))}
const result = await Axios('https://www.balldontlie.io/api/v1/teams')
const data = result.data;
//if you want to display all names
{
data.map(team => (
<div>
<h1 key={`${team.id}`}>{team.name}</h1>
</div>
)
}
//if you want to display all fields in each team
{
data.map(team => (
<div key={`${team.id}`}>
{
Object.keys(team).map((key, keyIndex) => (
<h1 key={`k-${team.id}-${keyIndex}`}>{team[`${key}`]}</h1>
))
}
</div>
)
}
Your response is an array
// you need to change this
Object.keys(items).map(item => (
<h1 key={item}>{item.data}</h1>
))}
// to this where items = result.data.data
items.map(item => <h1 key={item.id}>{item.city} </h1>
// to note here item.city need to be a string or number and not an objet
//if your data does not have an Id
items.map((item, index) => <h1 key={index}>{item.city} </h1>
and in your code this will become somthing like this
return (
<div>
{items.map((item, index) => <h1 key={index}>{item.city} </h1>}
</div>
)
Here an example how the complete code should looks, since you are seeing the response and data in console but not in the UI, it could be a state problem.
const App = () => {
const [items, setItems] = useState([]);
useEffect(()=>{
fetch('https://www.balldontlie.io/api/v1/teams')
.then(res => res.json())
.then(res => {
setItems(res.data);
})
.catch(error => {
//handle error here
});
},[])
return (
<>
{items.map(el => <h1 key={el.id}> el.city </h1>}
</>
)
}
As your data response is an array of objects and your requirement is to display attributes of that data, you can just run a simple loop on data and render items. Below "data" is the response from API
const data = [{"id":"1",name:"Team1"}, {"id":"2",name:"Team2"}]
data.map(item =>
<div>
<h1 key={id}>{item.name}</h1>
</div>
);
Related
I trying map data which i get using custom hook that recives data from my "storage" (which is actually a class with array of objects and async function to get them) i reciving an error: Cannot read properties of undefined (reading 'map').
Code of hook:
const useCreations = () => {
const service = new aboutPisanka();
const [data, setData] = useState();
useEffect(() => {
console.log(123 )
service.getAllCreations().then((data) => setData(data));
}, []);
return data
};
Code of element:
const data = useCreations();
console.log(data);
const cards = data.map((data) => {
const { heading, text, id, image } = data;
return (
<div key={id}>
<img src={require(image)}/>
<h1>{heading}</h1>
<p>{text}</p>
</div>
);
});
Code of function in class where data stores:
getAllCreations = async () => {
return this._creations;
};
(Sorry for my bad english)
As I understand it happens because it maps data before it gets to state but I don't have any idea how to fix it only making high order componen which will wrap my element.
Your data is initialize as undefined. So when the render runs before you assign an array value to data, your .map function fails because you call that on an undefined. Just initialize your data as an empty array.
const useCreations = () => {
const service = new aboutPisanka();
const [data, setData] = useState([]); // NOTE: Initialization as an empty array
useEffect(() => {
console.log(123 )
service.getAllCreations().then((data) => setData(data));
}, []);
return data
};
Also, you could use es6 de structuring to improve readability (subjective).
const data = useCreations();
console.log(data);
const cards = data.map(({ heading, text, id, image }) => (
<div key={id}>
<img src={require(image)}/>
<h1>{heading}</h1>
<p>{text}</p>
</div>
));
I do not see your whole code however if you are receiving data in correct format after a while because of Api response,you can add ? in cards const cards = data?.map((data) => { to fix that error
React is not rendering my mapped array after using asyn functions to call on API
I use the following useEffect to get characters into an array and set it as state in setRelatedCharacters
// Find related characters
useEffect(() => {
// for promise to work in useEffect. need to put async function inside then call it
const relatedCharacters = async () => {
// if data exist. set related characters array by calling utility function and wait for it
if (data) setRelatedCharacters(await relatedSwapi(data.characters));
};
relatedCharacters();
}, [data]);
Then, when logging relatedCharacters, I get an array of 17 objects(characters).
Next, I send a condition to wait until the array is full of characters and when full I try to map through the array and render a name for each object in array. However, it quickly flickers and then disappears. I have no idea why.
{!data && !relatedCharacters ? (
<Loading />
) : (
<div>
<p>hello</p> // renders
{console.log(relatedCharacters, "<= relatedCharacters")} // shows correct array
{relatedCharacters?.map((character) => (
<p key={character.name}>{character.name}</p> //DOESN'T SHOW, SLIGHTLY FLICKERS ONLY
))}
</div>
)
-- EDIT FOR COMMENT --
Here is the entire code once taking away everything else
const Film = () => {
const location = useLocation();
const url = location.state.url;
const index = location.state.index;
const [data, setData] = useState(null);
const [relatedCharacters, setRelatedCharacters] = useState(null);
// Find related characters
// PROBLEM HAS TO BE HERE I THINK AS PROMISES AND SUCH ARE ACTING UP
const relatedSwapi = (data) => {
let relatedArray = [];
data.map(async (url) => {
const related = await callSingleSwapi(url);
relatedArray.push(related);
});
return relatedArray;
};
useEffect(() => {
const fetchCharacters = async () => {
// if data exist. set related characters array by calling utility function and wait for it
if (data) {
const x = await relatedSwapi(data.characters);
setRelatedCharacters(x);
}
};
fetchCharacters();
}, [data]);
return (
<div>
<div className="relatedWrapper">
<div className="flex space-x-3">
{console.log(relatedCharacters, "<= related Characters")} // RENDERS AND THEN GOES BACK TO NULL
{relatedCharacters?.map((character) => (
<p key={character.name}>{character.name}</p>
))}
</div>
</div>
)}
</div>
);
};
export default Film;
Here is console.log(relatedCharacters)
I am having a small issue that I cannot seem to get right.
I am fetching data from Pokeapi to get some pokemon back, then iterating through that data in order to trigger another fetch request to bring back the associated data with a given pokemon.
I want to push this data to an array so that I can fire off this request as the application loads and save the data to storage so no new requests have to be made. However... (Which I have not done yet btw)
I console.log the results and the data is there, but when trying to map the data out, nada.
Please see my attempt below:
export function SomeComponent() {
let arr = [];
async function fetchPokemon() {
const pokemon = await fetch('https://pokeapi.co/api/v2/pokemon?limit=10')
.then(response => response.json())
for await (const x of pokemon.results.map(async (result) => await fetch(result.url)
.then(response => response.json()))) {
arr.push(x);
}
}
fetchPokemon();
console.log(arr)
return (
<>
{arr.map((pokemon) => (
<p>
{pokemon.name}
</p>
))}
</>
)
}
My best guess is that the console is displaying live results and that they data is not actually populated yet?
I would like to see the pokemon names displayed in the tag.
In react we should use state to store data and useEffect to do side effect actions like fetching data :
export function SomeComponent() {
const [arr, setArray] = useState([]);
async function fetchPokemon() {
const pokemon = await fetch('https://pokeapi.co/api/v2/pokemon?limit=10')
.then(response => response.json())
for await (const x of pokemon.results.map(async (result) => await fetch(result.url)
.then(response => response.json()))) {
setArray([...arr, x]);
}
}
useEffect(() => {fetchPokemon()}, []}
return (
<>
{arr.map((pokemon) => (
<p>
{pokemon.name}
</p>
))}
</>
)
}
I am playing around with an API that gets a list of Pokemon and corresponding data that looks like this.
export function SomePage() {
const [arr, setArray] = useState([]);
useEffect(() => {
fetchSomePokemon();
}, []);
function fetchSomePokemon() {
fetch('https://pokeapi.co/api/v2/pokemon?limit=5')
.then(response => response.json())
.then((pokemonList) => {
const someArray = [];
pokemonList.results.map(async (pokemon: { url: string; }) => {
someArray.push(await fetchData(pokemon))
})
setArray([...arr, someArray]);
})
}
async function fetchData(pokemon: { url: string; }) {
let url = pokemon.url
return await fetch(url).then(async res => await res.json())
}
console.log(arr);
return (
<div>
{arr[0]?.map((pokemon, index) => (
<div
key={index}
>
{pokemon.name}
</div>
))
}
</div>
);
}
The code works(kind of) however on the first render the map will display nothing even though the console.log outputs data. Only once the page has been refreshed will the correct data display. I have a feeling it's something to do with not handling promises correctly. Perhaps someone could help me out.
TIA
Expected output: Data populated on initial render(in this case, pokemon names will display)
The in-build map method on arrays in synchronous in nature. In fetchSomePokemon you need to return a promise from map callback function since you're writing async code in it.
Now items in array returned by pokemonList.results.map are promises. You need to use Promise.all on pokemonList.results.map and await it.
await Promise.all(pokemonList.results.map(async (pokemon: { url: string; }) => {
return fetchData.then(someArray.push(pokemon))
}));
On your first render, you don't have the data yet, so arr[0] doens't exist for you to .map on it, so it crashes. You need to check if the data is already there before mapping.
Using optional chaining, if there's no data it will not throw an error on your first render and it will render correctly when the data arrive and it re-renders.
...
return (
<div>
{arr[0]?.map((pokemon, index) => (
<div key={index}>{pokemon.name}</div>
))}
</div>
);
}
in
useEffect(() => { fetchSomePokemon(); }, []);
[] tells react there is no dependencies for this effect to happen,
read more here https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects
One way to solve your issues is to await the data fetching in useEffect().
Here's a POC:
export function Page() {
const [pokemon, setPokemon] = useState([]);
// will fetch the pokemon on the first render
useEffect(() => {
async function fetchPokemon() {
// ... logic that fetches the pokemon
}
fetchPokemon();
}, []);
if (!pokemon.length) {
// you can return a spinner here
return null;
}
return (
<div>
{pokemon.map(item => {
// return an element
})}
</div>
);
}
I have the following code :
export default function ProjectView({filteredProjects,revenueGroups}) {
const [projects,setProjects] = useState();
useEffect(() => {
const aap = filteredProjects.map(filteredObject => {
getProjectFields(filteredObject.projectId).then(res => {
filteredObject.rekt = res.data[0].id;
})
return filteredObject;
})
setProjects(aap);
},[filteredProjects])
And the rendered component :
return (
<div className='main'>
{projects.map(project => (
<div className='view-container' key={project._id}>
{console.log(project)}
</div>
))}
</div>
)
This works fine , when i console.log(project) like above it shows the following :
{
projectName: "privaye"
rekt: "project:1b1126ebb28a2154feaad60b7a7437df"
__proto__: Object
}
when i console.log(projectName) it shows the name, but when i console.log(project.rekt) it's undefined...
eventhough its there when i console.log(project)
EDITED
I didn't notice the was a promise inside :P
useEffect(() => {
fetchThings()
},[filteredProjects])
const fetchThings = async () => {
const promArr = filteredProjects.map(filteredObject => {
return getProjectFields(filteredProject.project.id)
})
const filteredObjects = await Promise.all(promArr)
const projectsMod = filteredObjects.map(fo => ({
...fo,
rekt: fo.data[0].id,
}))
}
Maybe an approach like this will help you with the asyncronous problem
console.log isn't rendering anything so maybe React doesn't try to refresh this part of the DOM when projects state is updated.
You can stringify the object to check the content of the variable inside the return
return (
<div className='main'>
{projects.map(project => (
<div className='view-container' key={project._id}>
<span>{ JSON.stringify(project) }</span>
</div>
))}
</div>
)
You are running promise, after this promise will return value you set rekt, but promise will work god knows when, and most probably you check value before this promise resolved.
getProjectFields(filteredObject.projectId).then(res => {
// THIS CODE CAN RUN AFTER RENDERING
filteredObject.rekt = res.data[0].id;
})
so first you wait till promises will complete and only then set new state
const ourPreciousPromises = filteredProjects.map(filteredObject =>
getProjectFields(filteredObject.projectId).then(res => {
filteredObject.rekt = res.data[0].id;
return {...filteredObject}
})
})
Promise.all(ourPreciousPromises).then(newObjects =>
setProjects(newObjects)
)