useEffect causing .map() error when sending post request - reactjs

When I try adding a new post I get this error. But when I console.log({ newPost }) I see that the new obj gets added. Something is happening when I try setting it in setPost({ newPost }).
import React, { useState, useEffect } from "react"
import axios from "axios"
const Users = () => {
const [posts, setPosts] = useState([])
useEffect(() => {
const getPosts = async () => {
const { data: post } = await axios.get(
"https://jsonplaceholder.typicode.com/posts"
)
setPosts(post)
}
getPosts()
}, [])
const handlePost = async () => {
const obj = {
title: "foo",
body: "bar",
userId: 1,
}
const { data: post } = await axios.post(
"https://jsonplaceholder.typicode.com/posts",
obj
)
const newPost = [post, ...posts]
setPosts({ newPost })
}
return (
<div>
<h1>List of all Posts</h1>
<button onClick={() => handlePost()}>Post new title</button>
<ul className="list-group list-group-flush">
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
)
}
export default Users

The error is that you are calling setPosts with an object when you mean it to be an array.
Replace
setPosts({ newPost })
With
setPosts( newPost )
This part doesn't really matter, but I would say that when dealing with async methods it's a better practice to setState with a function of the previousState rather than accessing the previous state directly.
setPosts((posts) => [post, ...posts])

posts state variable is expected to be an Array, so there's no need to set it inside an object. Change setPosts({ newPost }) to setPosts(newPost). It should work.

I run the code with the error in my pc so there are some errors.
But I changed setPosts(newPost).
So it is working very well.
If we avoid these errors, we should be familiar with React Hooks

Related

Uncaught TypeError: users.map is not a function - REACT

Please can someone help me look at this REACT code to see why i am getting the error "Uncaught TypeError: users.map is not a function". I have checked online and couldn't get an answer that is why i am posting something that looks like a question that has been asked before. Please help.
See code here:
import React, { useState, useEffect } from 'react';
const url = 'https://api.github.com/users';
const UseEffectFetchData = () => {
const [users, setUsers] = useState([]);
const getUsers = async () => {
const result = await fetch(url)
const Usrs = result.json()
setUsers(Usrs)
}
useEffect(() => {
getUsers();
}, []);
return (
<>
<h3>github users</h3>
<ul className='users'>
{
users.map((user) => {
const { id, login, avatar_url, html_url } = user;
return (
<li key={id}>
<img src={avatar_url} alt={login} />
<div>
<h4>{login}</h4>
<a href={html_url}>profile</a>
</div>
</li>
);
})
}
</ul>
</>
);
};
export default UseEffectFetchData;
You forgot to add “await” here:
const Usrs = await result.json()
Best regards!
In this case:
result.json() will return a promise.
you should use await to get json.
const getUsers = async () => {
const result = await fetch(url)
const Usrs = await result.json()
setUsers(Usrs)
}

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>
)
}

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>
);
};

Cannot read property 'map' of undefined on useState value

I'm new to react, I'm getting this error constantly and after google some I can't find the reason why the useState value can't be read as array :( ... this the error I'm getting: 'TypeError: team.map is not a function'
import React, { useEffect, useState } from "react";
const SportTeams = () => {
const [team, setTeam] = useState([]);
useEffect(() => {
const getSports = async () => {
const response = await fetch("https://www.thesportsdb.com/api/v1/json/1/all_sports.php");
const data = await response.json();
setTeam(data);
console.log(data);
}
getSports();
}, []);
return (
<div className="myClass">
<ul>
{team.map((sport, index) => {
return <li key={`${sport.strSport}-${index}`}>{sport.strSport}</li>
})}
</ul>
</div>
);
};
export default SportTeams;
Just update setTeam like following, your error will be resolved.
setTeam(data.sports);
It is because you are setting the team state with the data without checking if its undefined. If the data is undefined your state team become undefined as well. So make sure to check the data.
import React, { useEffect, useState } from "react";
const SportTeams = () => {
const [team, setTeam] = useState([]);
useEffect(() => {
const getSports = async () => {
const response = await fetch("https://www.thesportsdb.com/api/v1/json/1/all_sports.php");
if (response) {
const data = await response.json();
if (data) {
setTeam(data);
}
}
console.log(data);
}
getSports();
}, []);
return (
<div className="myClass">
<ul>
{team.map((sport, index) => {
return <li key={`${sport.strSport}-${index}`}>{sport.strSport}</li>
})}
</ul>
</div>
);
};
export default SportTeams;
There might also be the chance that your response is not what you expected and the actual data might be inside your response. In that case you need check what your response first then proceed to set the data.
As I said in my comment. the value you are setting to teams isn't an array.
const data = await response.json();
setTeam(data.sports);

Unhandled rejection(Typeerror):recipes.map is not a function

Image of error
this is the error am getting after running the app
what could be the problem when am rendering out this component in my parent component but after running it shows that map is not a function
import React, { useState, useEffect } from "react";
`import "./Meals.css";`
import Axios from "axios";
import RecipeCard from "./RecipeCard";
function Meals() {
const APP__KEY = "6d6112cdc44e4e44acb74c969b3624fd";
const [recipes, setRecipes] = useState([]);
useEffect(() => {
const getdata = async () => {
const result = await Axios.get(
`https://api.spoonacular.com/recipes/716429/information?apiKey=${APP__KEY}&includeNutrition=true.`
);
console.log(result.data);
setRecipes({
data: result.data,
});
};
getdata();
}, []);
return (
<div className="meals">
{recipes.map((recipe) => (
<RecipeCard recipe={recipe} />
))}
</div>
);
}
export default Meals;
I think in setRecipies function you are passing an object just pass array result.data assuming result.data is an array. you are passing {data:[]}. that is why you are getting object {data:[Array of data]} instead of array.
correct way is setRecipies(result.data)
Since you're working with recipes as with array, you shouldn't set it as object:
useEffect(() => {
const getdata = async () => {
const result = await Axios.get(
`https://api.spoonacular.com/recipes/716429/information?apiKey=${APP__KEY}&includeNutrition=true.`
);
console.log(result.data);
setRecipes(result.data); // set it as array, not an object
};
getdata();
}, []);

Resources