The component does not return an interface even if the props are supplied
I'm new to React, so I think the problem here is likely to be pretty simple. I am showing a list of regions, and when the user clicks on a region, I pass the object via props to the CountryList component:
render() {
return (
<div>
<SelectRegion
selectedRegion={this.state.selectedRegion}
onSelect={this.updateBoth} />
{ !this.state.countryCodes
? "Select a region"
: <CountryList countryCodes={this.state.countryCodes} /> }
</div>
)
}
The SelectRegion component works fine, but CountryList only provides a component with no content. Here is the CountryList component.
function CountryList(props) {
return (
<ul className="country-list">
{Object.entries(props.countryCodes).forEach(([key, val]) => {
return (
<li
key={key}
className="country-item" >
<div className="country-code">{key}</div>
<ul className="space-list-items">
<li>
<img
className="flag"
src={`http://www.geognos.com/api/en/countries/flag/${key}.png`}
alt={"Flag for " + val}
/>
</li>
</ul>
</li>
)
})}
</ul>
)
}
If I look in the inspector, I can see that when the user clicks on the area, the state is updated, the CountryList component is added to the page (as well <ul></ul>
) and that it has the appropriate props (object). What am I missing to render the component?
If useful, this is the whole component:
function App () {
return (
<div>
<Selector />
</div>
)
}
function SelectRegion (props) {
const regionCountry = {
"Europe": {
"PL": "Poland",
"HU": "Hungary",
"DE": "Germany",
"AT": "Austria",
"DK": "Denmark",
"ES": "Spain",
"GR": "Greece",
"IT": "Italy",
"CH": "Switzerland",
"RU": "Russia",
"FR": "France",
"BE": "Belgium",
"LU": "Luxembourg",
"SE": "Sweden",
"NO": "Norway",
"SI": "Slovenia",
"LT": "Lithuania",
"CY": "Cyprus",
"LV": "Latvia",
"BG": "Bulgaria",
"HR": "Croatia",
"GB": "United Kingdom",
"IE": "Ireland",
"GE": "Georgia",
"RO": "Romania",
"FI": "Finland",
"NL": "Netherlands",
"ME": "Montenegro"
},
"Americas": {
"CA": "Canada",
"US": "USA",
"MX": "Mexico",
"BR": "Brazil",
"CL": "Chile",
"AR": "Argentina",
"CO": "Columbia",
"UY": "Uruguay"
},
"APAC": {
"AU": "Australia",
"NZ": "New Zealand",
"KZ": "Kazakhstan",
"JP": "Japan",
"TH": "Thailand",
"TW": "Taiwan"
},
"Middle East & Africa": {
"IL": "Israel",
"TR": "Turkey",
"AE": "UAE",
"SA": "South Africa"
}
}
return (
<ul className="regions">
{Object.keys(regionCountry).map((region) => {
return(
<li
style={region === props.selectedRegion ? {color: '#d0021b'} : null}
onClick={props.onSelect.bind(null, region, regionCountry[region])}
key={region} >
{region}
</li>
)
})}
</ul>
)
}
function CountryList(props) {
return (
<ul className="country-list">
{Object.entries(props.countryCodes).forEach(([key, val]) => {
return (
<li
key={key}
className="country-item" >
<div className="country-code">{key}</div>
<ul className="space-list-items">
<li>
<img
className="flag"
src={"http://www.geognos.com/api/en/countries/flag/"+key+".png"}
alt={"Flag for " + val}
/>
</li>
</ul>
</li>
)
})}
</ul>
)
}
class Selector extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedRegion: null,
countryCodes: null
}
this.updateRegion = this.updateRegion.bind(this);
this.updateCountries = this.updateCountries.bind(this);
this.updateBoth = this.updateBoth.bind(this);
}
updateRegion(region) { selectedRegion: region }
updateCountries(countries) { countryCodes: countries }
updateBoth(updateRegion, updateCountries) {
this.setState(() => {
return {
selectedRegion: updateRegion,
countryCodes: updateCountries
}
})
}
render() {
return (
<div>
<SelectRegion
selectedRegion={this.state.selectedRegion}
onSelect={this.updateBoth} />
{ !this.state.countryCodes
? "Select a region"
: <CountryList countryCodes={this.state.countryCodes} /> }
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
)
body {
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
a {
text-decoration: none;
color: #d0021b;
}
ul {
padding: 0;
}
li {
list-style-type: none;
}
.button {
color: #e6e6e6;
background: #0a0a0a;
border: none;
font-size: 16px;
border-radius: 3px;
width: 200px;
text-align: center;
display: block;
padding: 7px 0;
margin: 10px auto;
}
.button:hover:enabled {
background: linear-gradient(#1a1a1a,#0a0a0a);
color: #fff;
text-decoration: none;
}
.button:active {
transform: translateY(1px);
}
.regions {
display: flex;
justify-content: center;
}
.regions li {
font-size: 1.5em;
margin: 10px;
font-weight: bold;
cursor: pointer;
}
.country-list {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
.country-item {
margin: 20px;
text-align: center;
}
.country-code {
margin: 20px;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello Express</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
source to share
Empty <ul></ul>
should mean props.countryCodes
not set, the loop for Object.entries looks good to me. The problem is that your "updateBoth" callback is to blame for onSelect={this.updateBoth}
not passing any parameters to updateBoth(updateRegion, updateCountries)
, so your state cannot set any value for countryCodes.
Edit
I can get your code to work with:
function CountryList(props) {
console.log(props);
return (
<ul className="country-list">
{
Object.keys(props.countryCodes).map((key) => {
console.log(key);
return (
<li
key={ key }
className="country-item" >
<div className="country-code">{key}</div>
<ul className="space-list-items">
<li>
<img
className="flag"
src={"http://www.geognos.com/api/en/countries/flag/"+key+".png"}
alt={"Flag for " + props.countryCodes[key]}
/>
</li>
</ul>
</li>
);
})
}
</ul>
)
}
source to share