I am trying to make an application from The movie data base api.
I came across a small problem.
I have two components. In first I use fetch and I use the map() function for the Card component in which I would like to display data from the api. How to connect them correctly?
https://codesandbox.io/s/p3vxqqz53q
First component for render list:
import React, { Component } from 'react';
import Card from "./Card";
class ListApp extends Component {
constructor(props){
super(props);
this.state = {
items: [],
isLoaded: false,
}
};
componentDidMount = () => {
fetch("https://api.themoviedb.org/3/movie/popular?api_key=xxxxxxxx&page=1")
.then(resp => resp.json())
.then(resp => {
this.setState({
isLoaded: true,
items: resp.results
})
console.log(this.state.items)
})};
render() {
var {isLoaded, items} = this.state;
return (
<div>
{items.map( () => ( <Card/> ) )};
</div>
);
}
}
export default ListApp;
Second component Card:
import React from 'react';
const Card = (items) => {
return (
<div className="movie-container">
<img src="https://image.tmdb.org/t/p/w185/{items.poster_path}" alt="NO PHOTO" className="movie-container__img" />
<div className="movie-container__about">
<span className="movie-container__percent">{items.vote_average}</span>
<h2 className="movie-container__title">{items.original_title}</h2>
<p className="movie-container__date">{items.release_date}</p>
<p className="movie-container__text">{items.overview}</p>
MORE
</div>
</div>
)
}
export default Card;
You need to pass the item object as a prop to the Card component like
{items.map(item => <Card key={item.id} item={item} /> )}
and then access item from within the Card component like
const Card = (props) => {
const {item} = props;
...
}
This code should work.
The map in the ListApp as #Aakash suggested:
render() {
var { isLoaded, items } = this.state;
return (
<div>
{items.map(item => (<Card key={item.id} item={item} />))};
</div>
);
}
An Card correctly referencing the item prop:
// Card.js
import React from 'react';
const Card = (props) => {
const { item } = props;
return (
<div className="movie-container">
<img src="https://image.tmdb.org/t/p/w185/{items.poster_path}" alt="NO PHOTO" className="movie-container__img" />
<div className="movie-container__about">
<span className="movie-container__percent">{item.vote_average}</span>
<h2 className="movie-container__title">{item.original_title}</h2>
<p className="movie-container__date">{item.release_date}</p>
<p className="movie-container__text">{item.overview}</p>
MORE
</div>
</div>
)
}
export default Card;
Related
I am trying to render a popup when a card is clicked. My problem is that I can't get the showPopup function running on click of the card component.
//... all required imports
class App extends Component {
constructor() {
super();
this.state = {
monsters: [],
searchField: ''
};
}
componentDidMount() {
// Fetches monsters and updates the state (working fine)
}
showPopup = () => {
console.log(2);
};
render() {
const { monsters, searchField } = this.state;
const filteredMonsters = monsters.filter(monster => monster.name.toLowerCase().includes(searchField.toLowerCase()));
return (
<div className="App">
<CardList className="name" monsters={filteredMonsters} showPopup={e => this.showPopup(e)} />
</div>
);
}
}
Following is the code for my CardList component
import React from 'react';
import { Card } from '../card/card.comp';
import './card-list.styles.css';
export const CardList = props => {
return (
<div className="card-list">
{props.monsters.map(monster => (
<Card key={monster.id} monster={monster} onClick={props.showPopup} />
))}
</div>
);
};
The onclick function above is not working as expected. Please help me find out the problem.
EDIT The code for card component
import React from 'react';
import './card.styles.css';
export const Card = props => {
return (
<div className="card-container">
<img src={`https://robohash.org/${props.monster.id}?set=5&size=150x150`} alt="Monster" />
<h2 key={props.monster.id}>{props.monster.name}</h2>
<p>{props.monster.email}</p>
</div>
);
};
I want to show the content on the cards (marked in red and named product.description in the code) on click but I don't know any way of doing it.
The content on the card is fetched from JSON-server.
Here is some code
The first js is used to fetch the data from the server and display
that on the page and the second one is the method of showing the data
on the page. In general, I want the p tag to appear and disappear
when the user clicks on the main div named Product-Preview
import { useEffect, useState } from "react";
import ProductList from "./ProductList";
const Products = () => {
const [products, setProducts] = useState (null);
useEffect (() => {
fetch('http://localhost:8000/products')
.then(res => {
return res.json();
})
.then(data => {
setProducts(data);
})
}, []);
return (
<div className="ProductList">
{products && <ProductList products={products}/>}
</div>
);
}
export default Products;
const ProductList = (props) => {
const products = props.products;
return (
<div className="ProductList" >
{products.map((product) => (
<div className="Product-Preview" key={product.id}>
<div className="backdrop" style={{backgroundImage: `url(${product.image})`}}></div>
<h2>{ product.title }</h2>
<p>{ product.description }</p>
<div>{ product.price }</div><br />
</div>
))}
</div>
);
}
export default ProductList;
You should create a component and use a state in this component to do it.
Example component has a name is Card
const Card= ({ product }) => {
const [showDescription, setShowDescription] = useState(false);
return (
<div
className="Product-Preview"
onClick={() => setShowDescription(!showDescription)}
>
<div className="backdrop" style={{ backgroundImage: `url(${product.image})` }}></div>
<h2>{product.title}</h2>
{showDescription && <p>{product.description}</p>}
<div>{product.price}</div>
<br />
</div>
);
};
And use this component inside map
{
products.map((product) => <Card product={product} key={product.id} />);
}
I' m new to React and I'm building a simple React app that displays all the nations of the world on the screen and a small search bar that shows the data of the searched nation.
Here an image of the site
But I don't know how to show the country you want to click in the scrollbar.
Here the app.js code:
import React, { Component } from 'react';
import './App.css';
import NavBar from '../Components/NavBar';
import SideBar from './SideBar';
import CountryList from '../Components/SideBarComponents/CountryList';
import Scroll from '../Components/SideBarComponents/Scroll';
import Main from './Main';
import SearchCountry from '../Components/MainComponents/SearchCountry';
import SearchedCountry from '../Components/MainComponents/SearchedCountry';
import Datas from '../Components/MainComponents/Datas';
class App extends Component {
constructor() {
super();
this.state = {
nations: [],
searchField: '',
button: false
}
}
onSearchChange = (event) => {
this.setState({searchField: event.target.value});
console.log(this.state.searchField)
}
onClickChange = () => {
this.setState(prevsState => ({
button: true
}))
}
render() {
const {nations, searchField, button, searchMemory} = this.state;
const searchedNation = nations.filter(nation => {
if(button) {
return nation.name.toLowerCase().includes(searchField.toLowerCase())
}
});
return (
<div>
<div>
<NavBar/>
</div>
<Main>
<div className='backgr-img'>
<SearchCountry searchChange={this.onSearchChange} clickChange={this.onClickChange}/>
<SearchedCountry nations={searchedNation}/>
</div>
<Datas nations={searchedNation}/>
</Main>
<SideBar>
<Scroll className='scroll'>
<CountryList nations={nations} clickFunc/>
</Scroll>
</SideBar>
</div>
);
}
componentDidMount() {
fetch('https://restcountries.eu/rest/v2/all')
.then(response => response.json())
.then(x => this.setState({nations: x}));
}
componentDidUpdate() {
this.state.button = false;
}
}
export default App;
The countryList:
import React from 'react';
import Images from './Images';
const CountryList = ({nations, clickFunc}) => {
return (
<div className='container' style={{display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(115px, 3fr))'}}>
{
nations.map((country, i) => {
return (
<Images
key={country.numericCode}
name={country.name}
flag={country.flag}
clickChange={clickFunc}
/>
);
})
}
</div>
)
}
export default CountryList;
And the images.js:
import React from 'react';
import './images.css'
const Images = ({name, capital, region, population, flag, numericCode, clickChange}) => {
return (
<div className='hover bg-navy pa2 ma1 tc w10' onClick={clickChange = () => name}>
<img alt='flag' src={flag} />
<div>
<h6 className='ma0 white'>{name}</h6>
{capital}
{region}
{population}
{numericCode}
</div>
</div>
);
}
export default Images;
I had thought of using the onClick event on the single nation that was going to return the name of the clicked nation. After that I would have entered the name in the searchField and set the button to true in order to run the searchedNation function.
I thank anyone who gives me an answer in advance.
To keep the actual structure, you can try using onClickChange in Images:
onClickChange = (newName = null) => {
if(newName) {
this.setState(prevsState => ({
searchField: newName
}))
}
// old code continues
this.setState(prevsState => ({
button: true
}))
}
then in onClick of Images you call:
onClick={() => {clickChange(name)}}
Or you can try as well use react hooks (but this will require some refactoring) cause you'll need to change a property from a parent component.
With that you can use useState hook to change the value from parent component (from Images to App):
const [searchField, setSearchField] = useState('');
Then you pass setSearchField to images as props and changes the searchField value when Images is clicked:
onClick={() => {
clickChange()
setSearchField(name)
}}
I have two components, the parent and child. Currently I have these codes below. But unfortunately it returns an error:
TypeError: Cannot read property 'click' of null
For some reasons I want when button is click the Item component also will be click. But these codes below produces an error above. Anyone does know how to achieve it?
import React, { useRef } from 'react';
const App = (props) => {
const itemRef = useRef(null);
return (
<div>
{dynamicBoolean ? (
<button onClick={() => itemRef.current.click()}>
click item
</button>
) : (
//more codes here
<Item ref={itemRef} />
)}
</div>
);
};
export default App;
Child component would look like below (demonstration purposes, the code is very lengthly)
import React from 'react';
const Item = (props) => {
return (
<div>
//some design here
</div>
);
};
export default Item;
You need useRef and you have to forward this ref to the Item component.
import React, { forwardRef, useRef } from 'react';
const Item = forwardRef((props, ref) => {
return <li {...props}
onClick={() => alert('clicked on Item')}
ref={ref} >MyItem</li>
})
const App = (props) => {
const itemRef = useRef(null);
return (
<div>
<button onClick={() => itemRef.current.click()}>
click item
</button>
<Item ref={itemRef} />
</div>
);
};
export default App;
import React, { createRef } from "react";
const Hello = (props) => {
const itemRef = createRef();
const hello = () => {
itemRef.current.click();
};
return (
<div>
<button onClick={() => hello()}>click item</button>
<Item ref={itemRef} />
</div>
);
};
const Item = React.forwardRef((props, ref) => {
const myClick = () => {
console.log("this is clicked");
};
return (
<button ref={ref} className="FancyButton" onClick={myClick}>
{props.children}
</button>
);
});
export default Hello;
This question already has an answer here:
List elements not rendering in React [duplicate]
(1 answer)
Closed 24 days ago.
I am going through a react course and currently learning react's lifecycle method. So far, I have been able to call the API using componentDidMount and have set the state. However, I can't seem to get the card components to show the images in the cardlist div. I'm sure I've done it correctly (looping through the state and creating a Card component with the props).
import react, {Component} from 'react';
import axios from 'axios';
import Card from './Card';
const api = ' https://deckofcardsapi.com/api/deck/';
class CardList extends Component {
state = {
deck: '',
drawn: []
}
componentDidMount = async() => {
let response = await axios.get(`${api}new/shuffle`);
this.setState({ deck: response.data })
}
getCards = async() => {
const deck_id = this.state.deck.deck_id;
let response = await axios.get(`${api}${deck_id}/draw/`);
let card = response.data.cards[0];
this.setState(st => ({
drawn: [
...st.drawn, {
id: card.code,
image: card.image,
name: `${card.value} of ${card.suit}`
}
]
}))
}
render(){
const cards = this.state.drawn.map(c => {
<Card image={c.image} key={c.id} name={c.name} />
})
return (
<div className="CardList">
<button onClick={this.getCards}>Get Cards</button>
{cards}
</div>
)
}
}
export default CardList;
import react, {Component} from 'react';
class Card extends Component {
render(){
return (
<img src={this.props.image} alt={this.props.name} />
)
}
}
export default Card;
import CardList from './CardList';
function App() {
return (
<div className="App">
<CardList />
</div>
);
}
export default App;
Your map function:
const cards = this.state.drawn.map(c => {
<Card image={c.image} key={c.id} name={c.name} />
})
does not return anything. So the result of this code is an array of undefined.
You have two options:
Add return:
const cards = this.state.drawn.map(c => {
return <Card image={c.image} key={c.id} name={c.name} />
})
Wrap in (), not {}:
const cards = this.state.drawn.map(c => (
<Card image={c.image} key={c.id} name={c.name} />
))
You should return the card component inside the map
const cards = this.state.drawn.map(c => {
return <Card image={c.image} key={c.id} name={c.name} />
})