I'm getting this compile error, but I'm unclear about what's undefined. This all looks like it should work, or at least not produce errors, but maybe I'm missing something obvious? Any assistance would be much appreciated. I'm happy to upload any additional code that might shed some light on the problem.

←→1 of 2 errors on the page
TypeError: Cannot read property 'map' of undefined
Persons.render
src/Components/Persons.jsx:14
  11 | }  
  12 | 
  13 |   render() {
> 14 |     let personsList = this.props.persons.map( (  persons, index) => {
     | ^  15 |       return <div className="personsListLinks"><li key={index}><Link to={`/api/persons/${persons.id}`}>{persons.name}</Link></li></div>
  16 |     })
  17 |     return (
View compiled

This is the Component:

import { BrowserRouter as Link } from "react-router-dom";

class Persons extends Component {
  constructor(props){
    super(props)
    this.state = {
      persons: '',
      personsList: ''
    }
  }  

    render() {
      let personsList = this.props.persons.map( (  persons, index) => {
        return <div className="personsListLinks"><li key={index}><Link to={`/api/persons/${persons.id}`}>{persons.name}</Link></li></div>
      })
      return (
        <div className="PersonsList">
        <h1>Persons</h1>
        {personsList}
      </div>
    )
  }
}
export default Persons;

And, App.jsx...

import './App.css';
import Signup from './Signup';
import Login from './Login';
import UserProfile from './UserProfile';
import { BrowserRouter as Router, Route, Link, Redirect } from "react-router-dom";
import axios from 'axios';
import PersonsShow from './Components/PersonsShow';
import Persons from './Components/Persons';
import { set } from 'mongoose';

class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      token: '',
      user: null,
      errorMessage: '',
      lockedResult: '',
      persons: [],
      personality: [],
      quotes: []
    }
    this.liftTokenToState = this.liftTokenToState.bind(this)
    this.checkForLocalToken = this.checkForLocalToken.bind(this)
    this.logout = this.logout.bind(this)
    this.handleClick = this.handleClick.bind(this)
    this.addNewPerson = this.addNewPerson.bind(this)
    // this.addQuote = this.addQuote.bind(this)

  }

  checkForLocalToken() {
    // Look in localStorage for the token
    let token = localStorage.getItem('mernToken')
    if (!token || token === 'undefined') {
      // There is no token
      localStorage.removeItem('mernToken')
      this.setState({
        token: '',
        user: null
      })
    } else {
      // Found a token, send it to be verified
      axios.post('/auth/me/from/token', {token})
      .then( res => {
        if (res.data.type === 'error') {
          localStorage.removeItem('mernToken')
          this.setState({errorMessage: res.data.message})
        } else {
          // Put token in localStorage
          localStorage.setItem('mernToken', res.data.token)
          // Put token in state
          this.setState({
            token: res.data.token,
            user: res.data.user
          })
        }
      })
    }
  }
  componentDidMount() {
    this.checkForLocalToken()
    this.getPersons()
  }

  getPersons = () => {
    axios.get('/persons')
    .then(res => {
        this.setState({
            persons: res.data
        })
    })
  }


  liftTokenToState({token, user}) {
    this.setState({
      token,
      user
    })
  }

  logout(){
    // Remove the token from localStorage
    localStorage.removeItem ('mernToken')
    // Remove the user and token from state
    this.setState({
      token: '',
      user: null
    })
  }

  handleClick(e) {
    e.preventDefault()
    // axios.defaults.headers.common['Authorization'] = `Bearer ${this.state.token}`
    let config = {
      headers: {
        Authorization: `Bearer ${this.state.token}`
      }
    }
    axios.get('/locked/test', config).then( res => {
      // console.log("this is the locked response:" , res);
      this.setState({
        lockedResult: res.data
      })
    })
  }

  handleNewPersonClick(person) {
    this.setState({
      person: person
    })
  }
  addNewPerson(e) {
    e.persist()
    e.preventDefault()
    let user = this.props.user
    let person = this.props.persons
    axios.post(`/api/user/:id/person${user._id}/`, {
      name: e.target.name
    }).then(res => {
      axios.get(`/api/user/${user._id}/persons`).then(res => {
        this.setState({persons: res.data})
      })
    })
  }

  render() {
    let user = this.state.user
    let contents;
    if (user) {
      contents = (
        <Router>
        <Route exact path='/' render= {() => <Redirect to='/persons' /> } />
        <Route exact path='/' render={() => <Persons persons={this.state.persons} user={this.state.user} logout={this.logout} />}/>
        {/* <Route path="/persons/:pid" render={(props) => <PersonsShow person={this.state.persons} addItem={this.addItem} user={user} logout={this.logout} {...props} />}/> */}
        {/* <Route path="/cart" render={() => <CartPage cart={this.state.cart} />}/> */}
        <UserProfile user={user} logout={this.logout} />
        <Persons person={this.state.persons} addItem={this.addItem} user={user} logout={this.logout}/>
        {/* <PersonsShow user={user} /> */}
          {/* <Persons user={user} /> */}
          {/* <p><a onClick={this.handleClick}>Test the protected route...</a></p> */}
          <p>{this.state.lockedResult}</p>
        </Router>
      )
    } else {
      contents = (
      <>
        <Signup liftToken={this.liftTokenToState} />
        <Login liftToken={this.liftTokenToState} />
      </>
      )
    }
    return (
      <div className="App">
        <header><h1>Welcome to Judge-O-Matic!</h1></header>
        <div className="content-box">
        {contents}
        </div>
      </div>
    )
  }
}

export default App;

I've tried rewriting as a functional component with similar results.

1 Answers

3
AryanJ-NYC On

You have a typo:

<Persons person={this.state.persons} addItem={this.addItem} user={user} logout={this.logout}/>

should be

<Persons persons={this.state.persons} addItem={this.addItem} user={user} logout={this.logout}/>

Please note the s at the end of the first prop.