How to render multiple items from an API call using React - javascript

I am using axios to get the data from an API. My component has an articles array in the state which is where the data from the API request will go.
I am still really new to React and trying to find information on displaying multiple articles on the page. That is what I am trying to figure out. Maybe I am using this.state wrong?
I've also tried fetch() then using a .then() to return the information. Neither way has helped me achieve what I am trying to display:
import React from "react";
import axios from "axios";
class Pages extends React.Component{
constructor(){
super();
this.state = {
articles : []
}
}
componentDidMount(){
this.getArticles().then(res =>
{
console.log(res);
this.setState({articles : res.data.articles});
});
}
getArticles(){
return axios.get('https://newsapi.org/v2/everything?domains=wsj.com,nytimes.com&apiKey=API_KEY');
};
render(){
return (
<div className="ui raised very padded text container segment">
<p>
Yo!
{this.state.articles[0] ? this.state.articles[0].author : ''}
</p>
</div>
);
}
}
export default Pages;
In the return section I want to display the article name, author, url link, and the content of the article.

If I understand correctly, you're wanting to render all articles that are available after your axios request completes.
To achieve that, consider using the map() method on the state.articles array. This allows you to "map" each item from the raw document JSON data to an <li> element containing the article information that you want to display to your users.
When rendering each <li>, you can access the content of the current article being mapped, to render that into the components overall rendered result:
render(){
return (
<div className="ui raised very padded text container segment">
<ul>
{ this.state.articles.map((article, index) => {
return (<li key={index}>
<h2>{ article.name }</h2>
<div>{ article.author }</div>
<p>{ article.content }</p>
<a href={article.url}>{ article.url }</a>
</li> )
})}
</ul>
<p>Yo!</p>
</div>
);
}
Something also to note is that, when rendering lists in React, you should include a unique key for each list item rendered (in the code above, the key is specified as the index of the article being mapped).
Update
To render the first article only (if present) while retaining your component's current state structure, you could slice() the articles array before performing the map(). This would cause a new array (with only the first article) to be passed to map() - the end result being that only the first article is rendered:
{ this.state.articles.slice(0,1).map((article, index) => {
/* Existing code from answer */
}}

Related

React JS Frontend - Key Error When Rendering List

I am getting the following error when rendering a list using ReactJS
react-jsx-dev-runtime.development.js:87 Warning: Each child in a list should have a unique "key" prop.
Check the render method of `DriverList`. See https://reactjs.org/link/warning-keys for more information.
at DriverList (http://localhost:3000/static/js/bundle.js:720:13)
at div
at Drivers (http://localhost:3000/static/js/bundle.js:1401:75)
at Routes (http://localhost:3000/static/js/bundle.js:47364:5)
at Router (http://localhost:3000/static/js/bundle.js:47297:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:46106:5)
at App
So far I have tried to unsuccessfully resolve it by adding the key value to both the Driver, a higher level div than the Driver object that doesn't need to be there, adding a key to the a React Fragment wrapped around the Driver object. I have tried adding it to each of them individually as well as multiple parts. I have also tried adding the key to the li item within the actual Driver object file that populates the DriverList. I still keep getting the error and I am thinking I am making a stupid mistake somewhere along the code that someone can point out and laugh at me for.
import React from "react"
import Driver from "./Driver"
import Card from "../../shared/components/interface/Card"
import "./DriverList.css"
const DriverList = (props) => {
if (props.items.length === 0) {
return (
<Card key='none'>
<h2>No drivers found.</h2>
</Card>
)
} else {
// Render the List
return (
<ul className='driver-list'>
{props.items.map((driver) => {
return (
<React.Fragment key={driver.id}>
<Driver
key={driver.id}
id={driver.id}
permitno={driver.permitno}
fname={driver.fname}
lname={driver.lname}
mailaddr1={driver.mailaddr1}
mailaddr2={driver.mailaddr2}
dateofbirth={driver.dateofbirth}
driversex={driver.driversex}
licenseidno={driver.licenseidno}
dvrclass={driver.dvrclass}
dvrpermit={driver.dvrpermit}
endorsemnt={driver.endorsemnt}
restricts={driver.restricts}
expdate={driver.expdate}
cmpldate={driver.cmpldate}
numpoints={driver.numpoints}
suspended={driver.suspended}
driver_status={driver.driver_status}
/>
</React.Fragment>
)
})}
</ul>
)
}
}
export default DriverList
try:
props.items.map((driver, idx) => {
return (
<Driver
key={idx}
and see if it helps. And if it does it means that driver.id repeats somewhere

How to get data from API "PokeAPI"

I have React component :
import React from "react";
import { Pokemons } from "../Pokemons";
class Main extends React.Component {
state = {
pokemons: [],
};
componentDidMount() {
fetch("https://pokeapi.co/api/v2/pokemon?limit=20")
.then((responce) => responce.json())
.then((data) => this.setState({ pokemons: Object.values(data) }));
}
render() {
return (
<main className="container content">
<Pokemons pokemon={this.state.pokemons} />
</main>
);
}
}
export { Main };
The API I'm using is PokeAPI
My task is to display data about the first 20 Pokémon (which is what I'm trying to do in fetch() ). But I don't get exactly what I need:
Console information.png
That is, JSON with four elements comes in response, the one I need is in the last one ( 3: ):
Console information 2.png
**In addition, each of the twenty objects (Pokémon) has a name and a link: **
Console Information 3.png
From this I need only the name, the rest of the necessary information (type, height, sprite) are data on these links. Example data in the link:
Data from link.png
In fact, the name of the pokemon is also in the data contained in these links.
I have never come across such an API structure before =(
Question - Help me get the name, type, sprite, height and weight of the Pokémon...
get rid of Object.values(data)
replace it with data.results
data contains the first layer of data, which includes count, next, results, etc...
you are interested in the results object, that contains the name, type, etc...
by doing data.results, you push the 20 pokemon objects to your state, then you can either
iterate over the array of objects and render <Pokemon /> for each pokemon
or
send the entire pokemon array to <Pokemon /> component and do that within the component itself.
example:
return (
<main className="container content">
{this.state.pokemons.map((pokemon) => (
<Pokemons pokemon={pokemon} />)}
</main>
);```
return (
<main className="container content">
<Pokemons pokemons={this.state.pokemons} />
</main>
);```
// Pokemons Component accepts pokemon array, and iterate it

TypeError: Cannot read properties of undefined (reading 'style')

Been stuck on debugging this for quite a while. I'm trying to have a group of items change onClick but with the use of transform but 'style' is undefined. I've also included the Card component functions. Help would be greatly appreciated
import React,{useRef} from 'react';
import { Card } from '../components';
import { CardItemContainer } from './card-item';
export function CardContainer()
{
const listRef=useRef()
const handleClick=(direction)=>
{
if(direction==="left")
{
listRef.current.style.transform=`translate(230)`
}
}
return(
<Card>
<Card.ListTitle> Continue to watch</Card.ListTitle>
<Card.Wrapper >
<Card.ArrowSliderLeft onClick={()=>handleClick('left')}/>
<Card.List ref={listRef}>
<CardItemContainer index={0}/>
<CardItemContainer index={1}/>
<CardItemContainer index={2}/>
<CardItemContainer index={3}/>
<CardItemContainer index={4}/>
<CardItemContainer index={5}/>
<CardItemContainer index={6}/>
</Card.List>
<Card.ArrowSliderRight onClick={() => handleClick("right")}/>
</Card.Wrapper>
</Card>
)
}
Card Components
import {ArrowBackIosOutlined,ArrowForwardIosOutlined} from "#material-ui/icons";
import React, {} from 'react';
import {
Container,
List,
ListTitle,
Wrapper,
ArrowSliderLeft,
ArrowSliderRight
} from './styles/card';
export default function Card({ children, ...restProps }) {
return <Container {...restProps}>{children}</Container>
}
Card.ListTitle=function CardListTitle({children,...restProps})
{
return <ListTitle{...restProps}> {children} </ListTitle>
}
Card.Wrapper=function CardWrapper({children,...restProps})
{
return <Wrapper{...restProps} > {children} </Wrapper>
}
Card.List=function CardList({children,...restProps})
{
return <List{...restProps} >{children}</List>
}
Card.ArrowSliderLeft = function HeaderArrowBackIosOutlinedSymbol({...restProps })
{
return <ArrowSliderLeft {...restProps }>
{/*id allows me to style the icon directly */}
<ArrowBackIosOutlined id="sliderLeft"/>
</ArrowSliderLeft>
}
Card.ArrowSliderRight = function HeaderArrowForwardIosOutlinedSymbol({...restProps}) {
return (
<ArrowSliderRight {...restProps}>
<ArrowForwardIosOutlined id="sliderRight"/>
</ArrowSliderRight>
);
};
Ignore:
Been stuck on debugging this for quite a while. I'm trying to have a group of items change onClick but with the use of transform but 'style' is undefined. I've also included the Card component functions. Help would be greatly appreciated
Function components like CardList don't have a ref property, only class components or DOM elements do.
You haven't posted List component's implementation, but let's assume it has a <ul> tag, and that is what you eventually need to manipulate its .style.transform
CardList >>> List >> ul (this is the element you need to pass the ref)
To pass the listRef all the way to ul from CardList you need to use the forwardRef technique.
Card.List=React.forwardRef(function CardList (props,ref)
{
const {children,...restProps} = props
return <List{...restProps} ref={ref} >{children}</List>
})
the List component itself :
const List = React.forwardRef(function (props,ref) {
return <ul ref={ref}>
... the implementation of your List
Now you can pass listRef in here and it goes down the chain:
<Card.List ref={listRef}>
Side Note: taking from Drew Reese's comment on this answer, since CardList is just transfering the same props from a parent component to List, you can simply assign List to Card.List, then only one step of ref forwarding would be enough:
Card.List = List // CardList component isn't used anymore.
The same thing could work for Card.ListTitle and Card.Wrapper:
Card.ListTitle=ListTitle
Card.Wrapper=Wrapper
I too have just faced this same issue, and have tried to get my code working again. Checking similarity between your given code and my erroneous code snippet helped me fix the error.
Strangely, I have faced this error with a JSX multi-line comment in place after my element (MUI <Snackbar> element, in my case).
Error(s):
My code snippet looked something like:
<Snackbar open={snackbarOpen} autoHideDuration={5000} onClose={()=>setSnackbar(false)} > {/* My Comment Here */}
<>...</>
</Snackbar>
Quite similar place of JSX comment as your Card Component
Card.ArrowSliderLeft = function
...
return <ArrowSliderLeft {...restProps }>
{/*id allows me to style the icon directly */}
<ArrowBackIosOutlined ... />
</ArrowSliderLeft>
Removing just the comment part {/* */} immediately following an opening tag worked for me.
So, try removing your JSX comment or placing it elsewhere,and see if it helps.
Sharing it here just for my and others future reference. :)

Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `Units`

This is only my second question here, so sorry if it's in the wrong place or has the wrong tags or anything.
import React from 'react';
import { connect } from 'react-redux';
import { getUnits } from '../reducers/units';
import { Menu, Container, Grid, Header, Form } from 'semantic-ui-react';
class Units extends React.Component {
componentDidUpdate(prevProps) {
const { dispatch, course } = this.props
if (prevProps.course.id !== course.id)
dispatch(getUnits(course.id))
}
units = () => {
return this.props.units.map( unit =>
<ul>
<li key={unit.id}> {unit.name}</li>
<button>Edit Module Name</button>
<button>Delete Module</button>
</ul>
)
}
render() {
return (
<Container>
<Header as="h3" textAlign="center">Modules</Header>
{ this.units() }
</Container>
)
}
}
const mapStateToProps = (state) => {
return { units: state.units, course: state.course }
}
export default connect(mapStateToProps)(Units);
I'm getting the error in the title of this question even though I have keys in the li elements and they are unique. I can see that they're different in the redux dev tools state, but for some reason I still get that error. I have looked at other similar errors here on stackoverflow but none of those seemed to solve this specific problem.
The answer #NorianNyx is good, basically you need to add an unique key to each component. However adding a index is not a good practice as this will not represent the item every single time. If you delete or add a new item to the list the index will change.
From React:
The best way to pick a key is to use a string that uniquely identifies a list item among its siblings. Most often you would use IDs from your data as keys
So the updated solution to this will be:
return this.props.units.map((unit) => (
<ul key={unit.id}>
<li> {unit.name}</li>
<button>Edit Module Name</button>
<button>Delete Module</button>
</ul>
));
In this way your item always will have an unique id
Your <ul> component needs a key prop.
Just change it to:
return this.props.units.map((unit, i) => (
<ul key={i}>
<li> {unit.name}</li>
<button>Edit Module Name</button>
<button>Delete Module</button>
</ul>
));

How to iterate through an array with React (Rails)

I just started to learn React and I am trying to figure out how to find a specific value I am looking for. Just like you have the each.do method in Ruby and you can iterate through an array, I'm trying to do that with React.
class Gallery extends React.Component {
render () {
// debugger;
return (
<div>
<img> {this.props.gallery.thumbnail_url} </img>
</div>
)
}
}
I am trying to access the thumbnail._url and when using the debugger, I am not able to access all the objects and images. I thought of this.props.gallery.object.thumbnail_url and other ideas but I am not really sure of the best way!
Use Array.prototype.map() to map the data to react elements. Not that elements rendered in a loop require a unique identifier (keys), to make rerendering list more performant.
class Gallery extends React.Component {
render () {
const { gallery = [] } = this.props; // destructure the props with a default (not strictly necessary, but more convenient)
return (
<div>
{
gallery.map(({ id, thumbnail_url }) => (
<img key={ id } src={ thumbnail_url } />
))
}
</div>
)
}
}
You can do something like this:
class Gallery extends React.Component {
render () {
// initialize 'images' to empty array if this.props.gallery is undefined
// other wise 'images.map' will throw error
const images = this.props.gallery || [];
return (
<div>
{images.map((image, index) => <img src={image.thumbnail_url} key={index} />)}
</div>
)
}
}
You may have noticed the prop key={index}. If you omit that, you will see a warning:
Each child in an array or iterator should have a unique "key" prop
Actually it is not passed to the component as prop but is used by React to aid the reconciliation of collections. This way React can handle the minimal DOM change.

Categories

Resources