What should I do to successfully map data from axios API? - reactjs

How do I map out the data I've put in my console/state? I've been trying to add a map function where I left the "//m", and it seems like it should be simple enough but I can't seem to do it properly.
import React, { useState, useEffect } from "react";
import axios from "axios";
import EmployeeDetail from "./EmployeeDetail";
function App() {
const [employees, setEmployees] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
axios.get("https://randomuser.me/api/?results=10&nat=us")
.then(res => {
console.log(res.data.results);
setEmployees(...res.data.results);
setLoading(false);
})
.catch(err => {
console.log(err);
});
}, []);
return (
<div className="App">
<h1>Employee List</h1>
//m
</div>
);
}
export default App;
I was able to make it using the API the guy in the youtube video I referenced used ("https://restcountries.eu/rest/v2/all") with the following function:
{countries.map((country) => (
<div key={country.name}>
{country.name} - {country-capital}
</div>
))}
I'm just having problems with doing it with my own API.

From your question it seems you are looking for rendering a table of output data from an API call.
When you call setEmployees(), react application will refresh the page using virtual DOM as you are setting a state using react hooks mechanism.
return(){
<div className="App">
<h1>Employee List</h1>
<table>
<thead>
// your table headers
</thead>
<tbody>
{this.employees.map((item, index) => {
<tr>
<td>{item.value1}</td>
<td>{item.value2}</td>
// as per your requirement
</tr>
})}
</tbody>
</table>
</div>
}
One more thing you can do is, create a function and return JSX from function.
Please visit below link for creating function and returning JSX.
How to loop and render elements in React.js without an array of objects to map?

You can use map as you want.
return (
<div className="App">
<h1>Employee List</h1>
<ul>
{
emplyees.map((employee) =>
<li>{employee.name}</li>
);
}
</ul>
</div>
);
There is a detailed document that you could follow step by step here

Related

React api calling and create same div by 'map' method

I want to call api and generate div using data from api, but I don't know why this code is not working. It doesn't show anything on the page.
This is my code. countryArray is an object array, and it has property of population, name, continent, capital.
import React from 'react'
function Countries() {
fetch("https://restcountries.com/v3.1/all")
.then((response)=>response.json())
.then((countryArray)=>{
return (
<div>
{countryArray.map((country)=>(
<div className="Country_wrapper">
<div className="Flag_wrapper">
</div>
<div className="Explanation_wrapper">
<h2>{country.name}</h2>
<p>Population: {country.population}</p>
<p>Region: {country.continents}</p>
<p>Capital: {country.capital}</p>
</div>
</div>
))}
</div>
)
},
(err)=>{
console.log(err);
})
}
export default Countries
Hello there first of all you need save the api data in a state and then fetch the api in useEffect then you can use the api data in your react app
import React , {useState , useEffect} from 'react';
function app() {
const [examples , setExamples] = useState([]);
useEffect(() => {
fetch('https://restcountries.com/v3.1/all')
.then((res) => res.json())
.then((data) => {
setExamples(data);
})
.catch((err) => console.log(err));
},[]);
return(
<>
<div>
{
examples.map((example) => (
<div className="Country_wrapper">
<div className="Flag_wrapper">
</div>
<div className="Explanation_wrapper">
<h2>{example.name.official}</h2>
<p>Population: {example.population}</p>
<p>Region: {example.continents}</p>
<p>Capital: {example.capital}</p>
</div>
</div>
))
}
</div>
</>
);
}
export default app
this code is working
You need to return a jsx element. The usual way of doing data fetching inside react component is to do it inside an effect.
A minimal example would be like this.
function Countries() {
const [countryArray, setCountryArray] = useState([]);
useEffect(() => {
(async function () {
const res = await fetch("https://restcountries.com/v3.1/all");
const json = await res.json();
setCountryArray(json)
})()
}, [])
return (
<div>
{countryArray.map((country)=>(
<div className="Country_wrapper">
<div className="Flag_wrapper">
</div>
<div className="Explanation_wrapper">
<h2>{country.name.common}</h2>
<p>Population: {country.population}</p>
<p>Region: {country.continents}</p>
<p>Capital: {country.capital}</p>
</div>
</div>
))}
</div>
)
}
Ofc you should also take care of race conditions, errors, loading states, or use a library that does all this stuff for you and more like react query.
Check the documentation for more information, fetching data
You can't return jsx from fetch, that won't be rendered.
Use useState inside a useEffect to save the data, then return from the functinon itself
const {useState, useEffect} = React;
function Countries() {
const [ data, setData ] = useState([])
useEffect(() => {
function getData() {
fetch("https://restcountries.com/v3.1/all")
.then((response) => response.json())
.then((countryArray) => setData(countryArray)
);
};
getData();
}, [ ]);
return (
<div>
{data.map((country)=>(
<div className="Country_wrapper">
<div className="Flag_wrapper">
</div>
<div className="Explanation_wrapper">
<h2>{country.name.common}</h2>
<p>Population: {country.population}</p>
<p>Region: {country.continents}</p>
<p>Capital: {country.capital}</p>
</div>
</div>
))}
</div>
)
}
ReactDOM.render(<Countries />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Demo takes quite some time to load, so here's a pic:

The given code using useselector is not fetching data

Here in functional component useSelector is not working and not fetching any images.I have also attached my codesandbox link below.
https://codesandbox.io/s/how-to-use-redux-in-your-react-app-with-axios-forked-sgzunt?file=/src/component/users.js
import React, { useEffect } from "react";
import { useSelector } from "react-redux";
import { getUsers } from "../store/actions/usersAction";
function Users(props) {
const users = useSelector((state) => state.users);
useEffect(() => {
getUsers();
}, []);
if (!users.length) return null;
const userData = users.map((user) => {
return (
<React.Fragment key={user.id}>
<h6> {user.first_name} </h6>
<p> {user.last_name} </p>
<p> {user.email}</p>
<p>
<img key={user.avatar} src={user.avatar} alt="avatar" />
</p>
</React.Fragment>
);
});
return <div>{userData}</div>;
}
export default Users;
I got a bit confused with your code. You are using a function that returns a function that takes dispatch as an argument, likely as part of a redux-thunk action creator (i.e. async actions). https://redux.js.org/tutorials/fundamentals/part-6-async-logic
You are updating your state with the users for userReducer object so your selector function should be state.users.users
I just updated with classic Js and it is working. I am trying to achieve your functionality by using nested arrow functions.
This is the working code in Classic Js.
users is empty when your components mount thats why its not rendering anything, the action is called in next line.
const [data,setData] = useState([])
useEffect(()=>{ setData(users) },[users])
replace below code
if (!data.length) return null;
replace map function too.
const userData = data.map((user) => {
return (
<React.Fragment key={user.id}>
<h6> {user.first_name} </h6>
<p> {user.last_name} </p>
<p> {user.email}</p>
<p>
<img key={user.avatar} src={user.avatar} alt="avatar" />
</p>
</React.Fragment>
);
});

React.js using onclick function to render a table

I have an array of objects coming from two different api. the first api I am converting it to a bullet point using
tag. and the second api should be converted to a table using tag. What I want to do is whenever I click on the bullet point it should show the table with the appropriate data. I was successfully able to get the data from both apis.
The main problem I am having is, the onClick function. First, after mapping the bullet point, the onclick function treat it as one gigantic click button. they are not seperated. Second, when I tried to hard code it , since they are only 8 bullet points. I was not able to get the data on a table.
I start coding just about a month and half ago, I have been trying everything I know for the last five days. At this point I ran out of ideas.
note that this is an example of only the fisrt table i have 8 more.
Please Help me guys thank you!
import React, { useEffect, useState } from 'react';
import './App.css';
const App = () => {
const reqMenu = "fake link";
const reqDescription = "fake link";
const [recipes, setRecipes] = useState([]);
const [description, setDescription] = useState([])
useEffect(() => {
getReq()
getDesc()
},[]);
const getReq = async () => {
const response = await fetch(reqMenu);
const data = await response.json()
setRecipes(data)
// console.log(data)
};
const getDesc = async () => {
const response= await fetch(reqDescription);
const data = await response.json()
setDescription(data)
// console.log(data)
}
const ss = description.filter((e) => (e.short_name.startsWith("SS")))
return (
<div className="App">
<h1>Menu Categories</h1>
<div>
<ul>
{recipes.map((recipe ,id, index) => (
<li key={id} onClick={() =>
{if(index[0] = recipes[0]["short_name"]){
return <table>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
{ss.map((s) =>{
<tr key={id}>
<td>{s.name}</td>
<td>{s.description}</td>
</tr>
})}
</table>
}}}>
{recipe.name}-({recipe.short_name})
</li>
))}
</ul>
</div>
</div>
);
}
export default App;
onClick doesn't accept a return value. What you want to do is conditionally render the components based on state from the onClick.
.map also does not have an id argument.
Also, JavaScript comparison is done using == or ===. Using a single = will do assignment, not comparison.
const initialListState = recipes.map(() => false);
const [listState, setListState] = useState(initialListState);
return (
<div className="App">
<h1>Menu Categories</h1>
<div>
<ul>
{recipes.map((recipe, index) => (
<li
key={index}
onClick={() => {
const newListState = [...listState];
newListState[index] = true;
setListState(newListState);
}
>
<table>
<thead
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{listState[index] && (
ss.map((s, sindex) => (
<tr key={sindex}>
<td>{s.name}</td>
<td>{s.description}</td>
</tr>
)
}
</tbody>
</table>
{recipe.name}-({recipe.short_name})
</li>
}
</ul>
</div>
</div>
);

Can React Testing Library find element after state change?

I'm absolutely new to react testing, learning from a playlist in youtube.
In this very moment of the tutorial, the instructor tests a component, which:
has a useEffect.
inside a useEffect, there is an axios.get
state is updated with api response.
state data is turned to elements (each has data-testid attribute equal to follower-item-{someNumber}.
The objective of the test is to find a data element.
. despite that i'm almost coping his code, his test passes, but mine doesn't. seems like the test runs before data fetching.
the component:
export default function FollowersList() {
const [followers, setFollowers] = useState([]);
useEffect(() => {
fetchFollowers();
}, []);
const fetchFollowers = async () => {
const { data } = await axios.get("https://randomuser.me/api/?results=5");
setFollowers(data.results);
};
return (
<div className="followerslist-container">
<div>
{followers.map((follower, ind) => (
<div className="follower-item" data-testid={`follower-item-${ind}`}>
<img src={follower.picture.large} />
<div className="followers-details">
<div className="follower-item-name">
<h4>{follower.name.first}</h4> <h4>{follower.name.last}</h4>
</div>
<p>{follower.login.username}</p>
</div>
</div>
))}
</div>
<div className="todo-footer">
<Link to="/">Go Back</Link>
</div>
</div>
);
}
The test:
const MockFollowersList = () => {
return (
<BrowserRouter>
<FollowersList />
</BrowserRouter>
);
};
describe("followers list", () => {
it("should render follower items", async () => {
render(<MockFollowersList />);
let el = await screen.findByTestId("follower-item-0");
expect(el).toBeInTheDocument();
});
});
result:
Unable to find an element by: [data-testid="follower-item-0"]
<body>
<div>
<div
class="followerslist-container"
>
<div />
<div
class="todo-footer"
>
<a
href="/"
>
Go Back
</a>
</div>
</div>
</div>
</body>
The problem is that you don't mock data. Try using https://www.npmjs.com/package/nock#debugging or something similar.
I recommend you to install and use eslint rule for testing library: https://github.com/testing-library/eslint-plugin-testing-library. This rule could help you avoid a common mistakes.

Dynamically rendering child components in react

I'm using firestore database to store my data in the collection "listings". So for each document in "listings", I need to render a <BookListing/> element in Home.js with the data from each document. From my research, there are a few other questions similar to this one out there, but they're outdated and use different react syntax. Here's my code:
function BookListing({id, ISBN, title, image, price}) {
return (
<div className="bookListing">
<div className='bookListing_info'>
<p className="bookListing_infoTitle">{title}</p>
<p className="bookListing_infoISBN"><span className="bookListing_infoISBNtag">ISBN: </span>{ISBN}</p>
<p className="bookListing_infoPrice">
<small>$</small>
{price}
</p>
</div>
<img className="bookListing_img" src={image} alt=""></img>
<button className="bookListing_addToCart">Add to Cart</button>
</div>
)
}
export default BookListing
function Home() {
document.title ="Home";
useEffect(() => {
getDocs(collection(db, 'listings'))
.then(queryCollection => {
queryCollection.forEach((doc) => {
console.log(doc.id, " => ", doc.data());
const element = <BookListing id="456" ISBN="0101" title="sample_title" image="https://nnpbeta.wustl.edu/img/bookCovers/genericBookCover.jpg" price="25"/>;
ReactDOM.render(
element,
document.getElementById('home-contents-main')
);
})
});
}, []);
return (
<div className="home">
<div className="home_container">
<div id="home-contents-main" className="home_contents">
</div>
</div>
</div>
)
}
export default Home
It's best (and most common) to separate the task into two: asynchronously fetching data (in your case from firestore), and mapping that data to React components which are to be displayed on the screen.
An example:
function Home() {
// A list of objects, each with `id` and `data` fields.
const [listings, setListings] = useState([]) // [] is the initial data.
// 1. Fetching the data
useEffect(() => {
getDocs(collection(db, 'listings'))
.then(queryCollection => {
const docs = [];
queryCollection.forEach((doc) => {
docs.push({
id: doc.id,
data: doc.data()
});
// Update the listings with the new data; this triggers a re-render
setListings(docs);
});
});
}, []);
// 2. Rendering the data
return (
<div className="home">
<div className="home_container">
<div className="home_contents">
{
listings.map(listing => (
<BookListing
id={listing.id}
ISBN={listing.data.ISBN}
title={listing.data.title}
image={listing.data.image}
price={listing.data.price}
/>
))
}
</div>
</div>
</div>
);
}
Some tips:
Fetching data from other web servers or services can be, and typically is, done in the same manner.
This example could be improved a lot in terms of elegance with modern JS syntax, I was trying to keep it simple.
In most cases, you don't want to use ReactDOM directly (only for the entry point of your app), or mess with the DOM manually; React handles this for you!
If you're not familiar with the useState hook, read Using the State Hook on React's documentation. It's important!
You can create a reusable component, and pass the data to it, and iterate over it using map() . define a state, and use it within the useEffect instead of creating elements and handling the process with the state as a data prop.
function BookListing({ id, ISBN, title, image, price }) {
return (
<div className="bookListing">
<div className="bookListing_info">
<p className="bookListing_infoTitle">{title}</p>
<p className="bookListing_infoISBN">
<span className="bookListing_infoISBNtag">ISBN: </span>
{ISBN}
</p>
<p className="bookListing_infoPrice">
<small>$</small>
{price}
</p>
</div>
<img className="bookListing_img" src={image} alt=""></img>
<button className="bookListing_addToCart">Add to Cart</button>
</div>
);
}
function Home() {
const [data, setData] = useState([]);
useEffect(() => {
document.title = 'College Reseller';
getDocs(collection(db, 'listings')).then((queryCollection) => setData(queryCollection));
}, []);
return (
<div className="home">
<div className="home_container">
<div id="home-contents-main" className="home_contents">
{data.map((doc) => (
<BookListing
id="456"
ISBN="0101"
title="sample_title"
image="https://nnpbeta.wustl.edu/img/bookCovers/genericBookCover.jpg"
price="25"
/>
))}
</div>
</div>
</div>
);
}
export default Home;

Resources