0

So far I have GET_TOURNAMENTS that sets all tournament objects in my state, and I render em on the page.

Then, I gave each tournament a button that calls showTournament() which selects whichever tournament I click, and updates the state. When I click SHOW_TOURNAMENT my state looks like:

tournament
  tournaments: [{...}, {...}]           <<~~this is from GET_TOURNAMENTS
  showTournament: {                     <<~~begins as (showTournament: "") until showTournament() action
    _id: "etc",
    title: "Tournament One",
    status: "Open",
    participants: [                          <<~~an array of User objects
      0: {_id: "asdf", username: "asdf"},
      1: {_id: "asdf", username: "asdf"}
    ]
  }

Annnnnnnnd I've attempted to render all of this in my ShowTournament component by doing:

class TournamentShow extends Component {
    static propTypes = {
        tournament: PropTypes.object.isRequired,
        auth: PropTypes.object.isRequired
    };

    render() {
        const { _id, title, hostedBy, status, participants } = this.props.tournament.showTournament;

        return (
            <div>
                <h1>{ title }</h1>
                <p>status: { status }</p>
                <p>Registered Participants:</p>
                {
                    participants ?
                    participants.forEach(participant => {
                        return (
                            <ul>
                                <li>{participant}</li>
                            </ul>
                        )
                    }) :
                    null
                }
                <p>Hosted by: { hostedBy }</p>
                <Link to="#">Sign Up</Link><br/>
                <Link to="/">Back to Tournaments main page</Link>
            </div>
        )
    }
};

const mapStateToProps = state => ({
    tournament: state.tournament,
    auth: state.auth
});

export default connect(mapStateToProps, { showTournament })(TournamentShow);

This shows nothing. Nothing is rendered even if there are Participants in the array.

I also tried simply <<~~ EDITED: I had the tags inside at first, put them outside the {}

                <p>Registered Participants:</p>
                <ul>
                  {
                      participants.forEach(participant => {
                          return (
                              <li>{participant}</li>
                          )
                      })
                  }
                </ul>

to which I get the error TypeError: Cannot read property 'forEach' of undefined

All the non-array data from the showTournament renders just fine.. I have found other Stack Overflow questions and tried a number of solutions but other questions are just different enough that I can't figure out how to get the right implementation.

Thanks all!

Cin88
  • 425
  • 2
  • 6
  • 20

2 Answers2

2

1) You need to use map because forEach doesn't return anything so whatever you're returning in forEach isn't even visible to outside world of forEach. map will return an array.

2) What are you trying to do by {participant}? It's an object, so either print it using JSON.stringify(participant) or better yet, print _id and username separately as shown below:

participants.map(participant => 
   (
      <ul>
         <li>{participant._id}</li>
         <li>{participant.username}</li>
      </ul>
   )
)

3) If you're getting an error as you say then it's likely that participants is undefined. Can you try debugging and see whether its values are populated or not. If debugging isn't possible, simply try printing it using

<div>{JSON.stringify(participants)}</div>

or even

<div>{JSON.stringify(this.props.tournament.showTournament)}</div>
chiragrtr
  • 902
  • 4
  • 6
  • To answer your initial question, i'm trying to merely render the list of participants on the page. But yes! That makes perfect sense. I was trying to render the Object in JSX instead of just their usernames. I tried your first solution but I'm still getting `undefined` The third code you wrote actually rendered something on the screen. I got the raw data at least. Looks like `Registered Fighters [{"_id":"1234", "username":"Dustin", etc}, {"_id":"2345", "username":"Cintron", etc}]` – Cin88 May 05 '20 at 19:50
  • Third code was stringified `this.props.tournament.showTournament`, right? From your output, it's clear that `participants` array doesn't exist inside `showTournament`. Also, there should be something between `Registered Fighters` and `[{"_id":"1234",..` The latter is an array. Its name (or key) is what you need, I think. Can you paste keys as well (right now we only see values is my guess)? – chiragrtr May 05 '20 at 19:55
  • Forgive me, I meant to say your SECOND code produced the raw data in the browser. It showed the participants. I also did the third, to see the showTournament itself and that renders the tournament data on the screen also. – Cin88 May 05 '20 at 19:59
  • 1
    I still don't understand what's `Registered Fighters` lol. Anyways, if you have the array then try these: Minimise all the css / styling stuff as well as other values by directly returning `
    {participants[0].username}
    ` In general, since you're able to print an object / array, you should be able to work your way inside that step by step e.g. We know that `participants` is an array (as printed) try `participants[0]` and then `participants[0].username` use `JSON.stringify` to your advantage
    – chiragrtr May 05 '20 at 20:06
  • 1
    Thank you. This was a big help. You and Nazar got me through it – Cin88 May 05 '20 at 20:08
1

First of all you need yo use Array.prototype.map() to render an array, Array.prototype.forEach() doesn't return anything to render, it just applies given function for each array item.

Then make sure you have the right data from a reducer, just set a breakpoint or use console.log to see thich data you are trying to render.

<ul>
  {
    participants.map(participant => (
      <li key={participant._id}>
        {participant.username}
      </li>
    ))
  }
</ul>
Nazar Litvin
  • 758
  • 6
  • 10
  • The rest of the showTournament's data is rendered fine.. and I tested it with multiple tournament objects. I believe I'm getting the right data. I just tried your solution even adding a unique key `participant[0]` and I tried `participant[0]._id` but i'm still getting the TypeError: cannot read property 'map' of undefined – Cin88 May 05 '20 at 19:36
  • `TypeError: cannot read property 'map' of undefined` mean's that you don't have proper data to render, your `participants` property is undefined. Did you try to set a breakpoint or log it to the console to make sure? – Nazar Litvin May 05 '20 at 19:40
  • Not entirely sure howt to set a breakpoint but console.log shows ` undefined (2) [{...}, {...}] ` There are 2 participants so that makes sense. But the first thing is 'undefined' ... – Cin88 May 05 '20 at 19:54
  • 1
    So you got this error because when render was called for the first times `participants` property was undefined. You can make sure that you will always have it, at least an empty array, or just use a condition `participants && participants.map(...)`. I strongly recommend the 1st option. p.s. Use `debugger` keyword to set a breakpoint or you can do it from your browser developer console. – Nazar Litvin May 05 '20 at 20:00
  • That worked! { participants && participants.map(participant => (
  • {participant.username}
  • )) } – Cin88 May 05 '20 at 20:07
  • Glad to help you! – Nazar Litvin May 05 '20 at 20:09