Reputation: 3044
Going through the next chapter in a react book I decided to try to build out some code to test out how props work in react. I have the following app:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
// Import Component
import PropExample from './simple-props'
const ctitle = "Sample app"
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">{ctitle}</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<div className='custom-components-list'>
<PropExample />
</div>
</div>
);
}
}
export default App;
Component PropExample
is making use of the container/containee design pattern. So it has two components within it PropX
and Card
. PropX the parent fetches data from an api and updates it's state. Card receives that data via props and renders it.
The code for both components is as follows:
/*
Simple component to read from api and present data
Propx to get data from api and function as container to Card component
Card component to present data to UI and leverage material ui
*/
import React, {Component} from 'react'
import Card from './card'
class PropX extends Component{
constructor(props){
super(props)
state:{
data:[{
name: 'Grrot',
city: "grav",
zip: 32453
},{
name: 'Grrot',
city: "grav",
zip: 32453
},{
name: 'Grrot',
city: "grav",
zip: 32453
}]
}
}
//Lifecycle hook that will grab data right before component is mounted to the dom
componentWillMount(){
let url = 'https://jsonplaceholder.typicode.com/users'
fetch(url)
.then((res)=>{ // Note that this a response object, need to look more into promises, fetch api and response object in javascript
//console.log(`The response is ${res}`)
return res.json()
})
.then(data => {
//console.log(`The data is ${data}`)
this.setState({data})
})
.catch(err=>{
console.log(`The error is ${err}`)
})
}
render(){
return(
<div>
<Card data={this.state}/>
</div>
)
}
}
export default PropX
And Card:
/*
Card component
Reads data fetched from parent PropX
Produces Cards with sylized data
*/
import React, {Component} from 'react'
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import Avatar from '@material-ui/core/Avatar';
import ImageIcon from '@material-ui/icons/Image';
import WorkIcon from '@material-ui/icons/Work';
class Card extends Component{
constructor(props){
super(props)
}
render(){
return(
<ul>
{this.props.data.map(i => {
return (
<li key={i}> {i.name}</li>
)
})}
</ul>
)
}
}
export default Card
When I run this I get the following error:
TypeError: Cannot read property 'map' of null
Card.render
card.js:21
18 | render(){
19 | return(
20 | <ul>
> 21 | {this.props.data.map(i => {
22 | return (
23 | <li key={i}> {i.name}</li>
24 | )
Removing this
doesn't fix the issue. Can anyone tell me what is wrong with this?
I am also trying to use material ui (installed with --save) but I'm not using any of the components as of yet since I can't figure out why I don't have data.
Upvotes: 0
Views: 90
Reputation: 2052
Your problem is in your constructor for PropX
constructor(props){
super(props)
state:{ // okay... so this is referenced where?
data:[{
name: 'Grrot',
city: "grav",
zip: 32453
},{
name: 'Grrot',
city: "grav",
zip: 32453
},{
name: 'Grrot',
city: "grav",
zip: 32453
}]
}
}
You need to assign state
as a property on this
in the constructor so that later when you pass it, it's actually assigned
constructor(props){
super(props)
this.state = { // now it's this.state
data:[{
name: 'Grrot',
city: "grav",
zip: 32453
},{
name: 'Grrot',
city: "grav",
zip: 32453
},{
name: 'Grrot',
city: "grav",
zip: 32453
}]
}
}
Of course now when you call .map()
in card you'll get a different error. What you probably wanted to do was pass this.state.data
to the card instead
render(){
return(
<div>
<Card data={this.state.data}/>
</div>
)
}
Upvotes: 1