Callat
Callat

Reputation: 3044

Simple prop example but props are not found

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

Answers (1)

Robert Mennell
Robert Mennell

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

Related Questions