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>
);
};
Related
This question already has answers here:
When to use ES6 class based React components vs. functional ES6 React components?
(7 answers)
Closed last month.
I have this error
error message : Cannot find name 'render'.ts(2304)
Then I did googling but couldn't find anything about render.
I don't know what's wrong with 'render'.
import React from "react";
import HoverButtons from "./HoverButtons";
const evStop = (ev:any) => {
ev.preventDefault();
ev.stopPropagation();
ev.nativeEvent.stopImmediatePropagation();
};
function HoverMenus () {
const state = { hiddenPopupMenu: true };
const toggle = () => {
this.setState({ hiddenPopupMenu: !this.state.hiddenPopupMenu });
};
const clkBtn = (ev:any, msg:any) => {
evStop(ev);
this.props.flashFn(msg);
};
// ***error message : Cannot find name 'render'.ts(2304)***
render() {
const p = {
funcs: {
interested: (e:any) => this.clkBtn(e, "interested"),
}
};
return (
<div className="whenhovered" onClick={this.toggle}>
{this.state.hiddenPopupMenu && (
<div>
<div className="mt-5 pt-5" />
<div className="mt-5" />
<HoverButtons
txt="LIKE"
icon="thumbs-up"
clicked={p.funcs.interested}
/>
</div>
)}
</div>
);
}
}
export default HoverMenus;
You mixed between a class component and a function component,
To use class component convert your function to a class and add extends React.Component to your class:
class HoverMenus extends React.Component {
}
To use function component, you will need to change the syntax acording to https://reactjs.org/docs/components-and-props.html
The 'render' is a class component method. It does not work in functional components.
Try this:
import {useState} from 'react'
function HoverMenus (props) {
const [hiddenPopupMenu, setHiddenPopupMenu] = useState(true)
const toggle = () => {
setHiddenPopupMenu(!hiddenPopupMenu);
};
const clkBtn = (ev:any, msg:any) => {
ev.stopPropagation();
props.flashFn(msg);
};
const p = (e:any) => clkBtn(e, "interested");
return (
<div className="whenhovered" onClick={toggle}>
{hiddenPopupMenu && (
<div>
<div className="mt-5 pt-5" />
<div className="mt-5" />
<HoverButtons
txt="LIKE"
icon="thumbs-up"
clicked={p}
/>
</div>
)}
</div>
);
}
export default HoverMenus;
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)
}}
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} />
})
I am doing a small project and have a list of components that display information about countries. Now I have added react router so that when I click on a card it displays more information about that country. Now when I click on the card nothing happens! Below is the code for the Countries.
import React, { Component } from 'react';
import { CountryList } from './Components/Card-List/CountryList';
import { SearchBox } from './Components/Search-box/Search-Box';
import './Countries.styles.css';
import { DetailCountryCard } from './Components/DetailCountryCard/DetailCountryCard';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
class Countries extends Component {
constructor() {
super();
this.state = {
countries:[],
searchField:"",
regionField:"",
darkMode: false
}
this.setDarkMode = this.setDarkMode.bind(this);
};
componentDidMount() {
fetch("https://restcountries.eu/rest/v2/all")
.then(response => response.json())
.then(all => this.setState({ countries: all,
regions: all}))
.catch(error => console.log("I have errored" + error));
}
setDarkMode(e){
this.setState((prevState) => ({ darkMode: !prevState.darkMode }));
}
render() {
const { countries, searchField, regionField, darkMode } = this.state;
const filterCountries = countries.filter((country) => country.name.toLowerCase().includes(searchField.toLowerCase()) &&
country.region.toLowerCase().includes(regionField.toLowerCase()));
return(
<Router>
<div className={darkMode ? "dark-mode" : "light-mode" }>
<nav className="navbar-items">
<h1 className="header">Where in the World</h1>
<div className="moon-end">
<button onClick={this.setDarkMode}>
<i className={darkMode ? "moon fas fa-moon" : "moon far fa-moon" }></i>
</button>
<h2>{darkMode ? "Dark Mode" : "Light Mode" }</h2>
</div>
</nav>
<div className="Input">
< SearchBox type="search" placeholder="Search a Country" handlechange={e=> this.setState({
searchField: e.target.value })}
/>
< SearchBox type="regions" placeholder="Filter by Regions" handlechange={e=> this.setState({
regionField: e.target.value })}
/>
</div>
<CountryList countries={filterCountries} />
{/* <Route path="/" exact component={Countries} /> */}
<Switch>
<Route path="/card-detail/:name" component={ DetailCountryCard } exact/>
</Switch>
</div>
</Router>
);
}
}
export default Countries
The link for each card is in the following component:
import React from 'react';
import './CountryList.styles.css';
import {Link} from 'react-router-dom'
import { CountryCard } from '../Card/CountryCard';
export const CountryList = (props) => (
<div className='card-list'>
{props.countries.map(country => (
<Link to={`/card-detail/${country.name}`} >
<CountryCard key={country.alpha2Code} country={country} />
</Link>
))}
</div>
);
This should go to the following component:
import React from 'react';
import { useEffect } from 'react';
import { useState } from 'react';
export const DetailCountryCard = ({match}) => {
useEffect(() => {
fetchItem();
console.log(match);
},[])
const [country, setCountry] = useState([])
const fetchItem = async ()=> {
const fetchCountry = await fetch(`https://restcountries.eu/rest/v2/name/${match.params.name}`);
const countries = await fetchCountry.json();
setCountry(countries);
console.log(country);
}
return (
<div>
{country.map(town => (
<div>
<h1 key={town.alpha2Code}>{town.name}</h1>
<p>Native Name{town.nativeName}</p>
<p>Region: {town.region}</p>
<p>Languages: {town.languages[0].name}</p>
</div>
))}
</div>
);
}
Not sure what I am missing. I don't think I have done a typo on the component. So not sure why it is not rendering? Any help would be appreciated.
You just need add dependency of match in useEffect in DetailCountryCard. Because [] its similar in Class ComponentcomponentDidMount()` and you need to listen when match it's changed.
This is final code to DetailCountryCard:
import React from "react";
import { useEffect } from "react";
import { useState } from "react";
export const DetailCountryCard = ({ match }) => {
useEffect(() => {
fetchItem();
console.log(match);
}, [match]);
const [country, setCountry] = useState([]);
const fetchItem = async () => {
const fetchCountry = await fetch(
`https://restcountries.eu/rest/v2/name/${match.params.name}`
);
const countries = await fetchCountry.json();
setCountry(countries);
console.log(country);
};
return (
<div>
{country.map(town => (
<div>
<h1 key={town.alpha2Code}>{town.name}</h1>
<p>Native Name{town.nativeName}</p>
<p>Region: {town.region}</p>
<p>Languages: {town.languages[0].name}</p>
</div>
))}
</div>
);
};
I tested in CodeSandBox and it works!
Link
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;