React .map an object - reactjs

I've got an eslint error Property 'date' does not exist on type 'never', and it's on data.date. Any idea how can I fix it?
import React from 'react'
import app from './../Flamelink'
function App() {
const [data, setData] = React.useState([])
React.useEffect(() => {
const fetchData = async () => {
const data = await app.content.get({
schemaKey: 'persons'
})
setData(data)
}
fetchData()
}, [])
return (
<ul>
{data.map(data => (
<li>{data.date}</li>
))}
</ul>
)
}
export default App

First of all, I would use a different variable name instead of just calling everything data. This way you avoid variable shadowing errors.
If you want your state variable to be data then call the answer you get from your fetch something else, result maybe. Then, when mapping your data state, call the current value something else too, maybe item or dataItem.
Second, since you appear to be using TypeScript, you need to tell TS the structure of your data state array.
Try this:
function App() {
const [data, setData] = React.useState<Array<{date: string}>>([]);
React.useEffect(() => {
const fetchData = async () => {
const result = await app.content.get({
schemaKey: "persons"
});
setData(result);
};
fetchData();
}, []);
return (
<ul>
{data.map(item=> (
<li>
{item.date}
</li>
))}
</ul>
);
}

Related

How do I map through an unnamed array in React?

I have an array that looks like this.
[{"id":19,"name":"asd","salary":123},{"id":20,"name":"wer","salary":1}]
But when I try to map through it in React I get an Error
Uncaught TypeError: data.map is not a function
import React, { Component, useState, useEffect } from 'react';
function EmployeeList() {
const [data, setData] = useState({ items : [] });
const getEmployees = () => {
fetch("http://127.0.0.1:8000/api/employee-list")
.then((response) => response.json())
.then((data) => {
setData(data);
console.log(data);
})
};
useEffect(() => {
getEmployees();
}, [])
return (
<div>
<ul>
{data.map((employee) =>
<li>{employee.name}</li>
)}
</ul>
</div>
)
export default EmployeeList;
That's because you are not setting data to an array, but an object at first. Use this instead:
const [data, setData] = useState([]);
This assumes that your data comes back from the API as you specified, i.e., as an array. If instead it comes back in the format suggested by your original initial value then you'd need to use:
{data && data.items && data.items.map((employee) =>

React Typescript fetch: useState UseEffect pokeapi

I am trying to learn how to fetch data and display in a table/list/graph in React.
I extracted the fetch to a component and while i can get the list to appear i think this is wrong - Why and how to fix?
// getData.tsx
import React, { useState, useEffect } from 'react';
let myArray: string[] = [];
export default function GetData() {
const [info, setData] = useState([]);
useEffect(() => {
getMyData();
}, []);
const getMyData = async () => {
const response = await fetch('https://pokeapi.co/api/v2/type')
const data =await response.json();
//console.log(data.results)
for (var i = 0; i < data.results.length; i++) {
myArray.push(data.results[i].name)
setData(data.results[i].name)
}
console.log(info)
}
return (
<div>
<h1>get Data</h1>
{myArray.map((value,index) => {
return <li key={index}>{value}</li>;
})}
</div>
)
}
Also same issue but do not understand why the names and Array don't both work?
export default function GetData(){
const names: string[] = ["whale", "squid", "turtle", "coral", "starfish"];
const theArray: string[] = [];
const getData = async () => {
const response = await fetch('https://pokeapi.co/api/v2/type');
const data = await response.json()
//for (var i = 0; i < data.results.length; i++) {
for (var i = 0; i < 5; i++) {
theArray.push(data.results[i].name)
}
console.log(theArray)
}
console.log(names)
console.log(theArray)
getData()
return (
<div>
<ul>{names.map(name => <li key={name}> {name} </li>)}</ul>
<h1>get Data</h1>
<ul>{theArray.map(name => <li key={name}> {name} </li>)}</ul>
</div>
)
}
You aren't using the state data... The issue is that.
The correct way to do this:
const [data, setData] = useState([])
useEffect(() => {
fetch('https://pokeapi.co/api/v2/type')
.then(res => res.json())
.then(setData)
},[])
return <div>
<ul>
{data.map((name) => <li key={name}>{name}</li>}
</ul>
</div>
The problem is getData is declared as async function. That means it's returning Promise that you can await on and get it's result. But you never do that. You're using it without await essentially not waiting for it finish and discarding its result.
To get the result of async function you should await on it. In your second component you'll have to write this:
...
console.log(names)
console.log(theArray)
await getData() // add 'await' to well... wait for the result of the getData execution
return (
...
But you can await only inside async function aswell. As far as I'm concerned you're not able to use async components now (react#16-17). So the second component is not going to work as intended. At least untill react is able to support async components.
Though there are some issues even with your first component.
let myArray: string[] = [];
Declared in the module scope it will be shared (and not reseted) between all instances of your component. That may (and will) lead to very unexpected results.
Also it's quite unusuall you don't get linting errors using getMyData before declaring it. But I suppose that's just an artefact of copy-pasting code to SO.
Another problem is you're using setData inside your component no to set the contents of myArray but to trigger rerender. That's quite brittle behavior. You should directly set new state and react will trigger next render and will use that updated state.
To work properly your first component should be written as:
import React, { useState, useEffect } from 'react'
export default function GetData() {
const [myArray, setMyArray] = useState([])
const getMyData = async () => {
const response = await fetch('https://pokeapi.co/api/v2/type')
const data = await response.json()
const names = data.results.map((r) => r.name) // extracting 'name' prop into array of names
setMyArray(names)
}
useEffect(() => {
getMyData();
}, []);
return (
<div>
<h1>get Data</h1>
{myArray.map((value,index) => (
<li key={`${index}-${value}`}>{value}</li>
))}
</div>
)
}

I receive "TypeError: items is undefined" when trying to map items from a JSON

I am currently trying to setup a React web app using React hooks. I try to pull the items from the JSON with Map but I receive this error.
TypeError: items is undefined
Shop.js
import React, {useState, useEffect} from 'react';
import './App.css';
function Shop() {
useEffect(() => {
fetchItems();
}, []);
const [items, setItems] = useState([]);
const fetchItems = async () => {
const data = await fetch('https://fortnite-api.theapinetwork.com/upcoming/get');
const items = await data.json();
console.log(items.items);
setItems(items.items);
};
return (
<div>
{items.map(item => (
<h1>{item.map}</h1>
))}
</div>
);
}
export default Shop;
I'm not an expert on React, but I'm pretty sure its because you get to the return statement before you define items.
That function is async, so while it takes its turn running each line, the program itself will move on, thus getting to the return with "items" in it before items is actually defined.
What might fix it is doing an if/else that checks if items is defined, then returns either blank html or the html with items. React dynamically updates so that should then return the correct html once items is loaded.
This should solve your question. I have checked the response from the GET request you provided and you have used the incorrect data structuring when pulling fields out. Try the code below.
import React, {useState, useEffect} from 'react';
import './App.css';
function Shop() {
useEffect(() => {
fetchItems();
}, []);
const [items, setItems] = useState([]);
const fetchItems = async () => {
const response = await fetch('https://fortnite-api.theapinetwork.com/upcoming/get');
const deserialisedResponse = await response.json();
setItems(deserialisedResponse.data);
};
return (
<div>
{items.map((item, index) => (
<h1 key={index}>{item.map}</h1>
))}
</div>
);
}
export default Shop;
I've tried on my end and confirmed it works.
Let me show the codes.
function Shop() {
useEffect(() => {
fetchItems();
}, []);
const [items, setItems] = useState([]);
const fetchItems = async () => {
const response = await fetch('https://fortnite-api.theapinetwork.com/upcoming/get');
const deserialisedResponse = await response.json();
console.log("result: ", deserialisedResponse)
setItems(deserialisedResponse.data);
};
return (
<div>
{items.map((item, idx) => (
<h1 key={idx}>{item.item.name}</h1>
))}
</div>
)
}
Please have a check and let me know if it works or not.

Getting map data using React from firestore

I am having trouble trying to figure out how to get map data from Firestore in reactjs. My code keeps erroring saying "Objects are not valid as a React". Can someone point me to an example or show me one with my database below?
import React, { useState, useEffect } from "react";
import { firestore } from "../../../FireBase/FireBase";
import CartItem from "./CartItem";
const CartPage = (props) => {
const [cart, setCart] = useState(null);
useEffect(() => {
const fetchCart = async () => {
const doc = await firestore
.collection("Users")
.doc("CfL5uszL3CTE1nIQTgDrKK5q4OV2")
.get();
const data = doc.data();
console.log("data " + data);
if (!data) {
// document didn't exist
console.log("hit null");
setCart(null)
} else {
console.log("hit");
setCart(data.cart);
}
console.log("cart " + cart);
}
fetchCart();
}, []);
if (!cart) {
// You can render a placeholder if you like during the load, or just return null to render nothing.
return null;
}
return (
<div className="cartpage">
<h1>cart</h1>
<div className="cart">
{cart.map(cartItem => (
<div key={cartItem.id}>{cartItem.name}</div>
))}
</div>
</div>
);
};
export default CartPage;
The error your getting is because you're returning a promise from your component (You've made it an async function, and async functions return promises). Promises and other arbitrary objects cannot be returned from rendering in react. You need to have a state variable for holding your data. On the first render, you'll have no data, and then you'll use a useEffect to fetch the data and update the state
Additionally, you have some mistakes with how you're trying to get the data and access it. You're calling .get("Cf...V2"), but .get doesn't take a parameter. If you want to specify which document to get, you use the .doc() function for that. .get() will then return a promise, so you need to await that before trying to access any properties on it. The data you get will be an object with all the properties on the right hand side of your screenshot, and you will need to pluck the cart property out of that.
In short, i recommend something like the following:
const CartPage = (props) => {
const [cart, setCart] = useState(null);
useEffect(() => {
const fetchCart = async () => {
const doc = await firestore
.collection("Users")
.doc("CfL5uszL3CTE1nIQTgDrKK5q4OV2")
.get();
const data = doc.data();
if (!data) {
// document didn't exist
setCart(null)
} else {
setCart(data.cart);
}
}
fetchCart();
}, []);
if (!cart) {
// You can render a placeholder if you like during the load, or just return null to render nothing.
return null;
}
return (
<div className="cartpage">
<h1>cart</h1>
<div className="cart">
{cart.map(cartItem => (
<div key={cartItem.id}>{cartItem.name}</div>
))}
</div>
</div>
);
};
I don't think so that you can create async component in this way. What you return in your component should be simple JSX code. If you want to do something asynchronously inside component you should wrap this inside useEffect hook.
const CartPage = (props) => {
const [ cart, setCart ] = useState(null)
useEffect(() => {
const inner = async () => {
const ref = await firestore
.collection("Users")
.get("CfL5uszL3CTE1nIQTgDrKK5q4OV2").cart;
setCart(
ref.map((item) => ({
id: item.id,
name: item.name
}))
);
};
inner();
}, []);
return (
<div className="cartpage">
<h1>cart</h1>
<div className="cart"></div>
</div>
);
};

data coming from custom fetch hook and local state

I want to have a local setter to update data I'm extracting from custom fetch hook:
function ContactList(props) {
const contacts =useFetch(fetchUrl, []);**//contain data**
const [data,setData] = useState(contacts);**//remains empty**
return (
<div>
<Navbar />
<ul className="collection">
<ContactItem contacts={contacts} setContacts={setData} />
</ul>
</div>
);
}
fetchHook looks like this:
export const useFetch = (url, initialValue) => {
const [result, setResult] = useState(initialValue);
useEffect(() => {
const fetchData = async () => {
const result = await axios(url);
setResult(result.data.contact);
};
fetchData();
}, []);
return result
}
so I need the contactList to have a setter which I currently don't manage to achieve because state remain an empty array.
const contacts =useFetch(fetchUrl, []);
useFetch is asynchronous and makes the call and gives the result after the componentMounts, since I'm assuming you put that in a useEffect with empty dependency in your hook.
So, the data won't be available on the first render, making it initialize to empty.
EDIT:
To understand better, follow the console.log in the following example:
https://codesandbox.io/embed/friendly-ives-xt5k0
You'll see that it is empty first and then it gets the value.
Now, the same is the case in your code. On the first render it's empty and that is when you set the state of result. Instead, you can just use the value of contacts in your case.
EDIT 2:
After seeing what you need, all you have to do is to also return the setResult from the hook:
export const useFetch = (url, initialValue) => {
const [result, setResult] = useState(initialValue);
useEffect(() => {
const fetchData = async () => {
const result = await axios(url);
setResult(result.data.contact);
};
fetchData();
}, []);
return {result, setResult}
}
function ContactList(props) {
const {result, setResult} =useFetch(fetchUrl, []);
return (
<div>
<Navbar />
<ul className="collection">
<ContactItem contacts={result} setContacts={setResult} />
</ul>
</div>
);
}

Resources