0

I'm trying to remove the duplicates from an array.map function in React and I'm not sure why I'm getting a "Cannot read property of undefined" error.

The below code does not return any results, which is what I expected because video.project.id is equal to videos[i].project.id:

this.props.videos.map((video, i, videos) => {
    if (video.project.id !== videos[i].project.id) {
        return (
            <option
                key={video.id}
                value={video.project.id}
            >
              {video.project.projectName}
            </option>
        )
    }
})

So I would think the below code should return one of each entry but I instead get the error:

this.props.videos.map((video, i, videos) => {
    if (video.project.id !== videos[i - 1].project.id) {
        return (
            <option
                key={video.id}
                value={video.project.id}
            >
              {video.project.projectName}
            </option>
        )
    }
})

Can anyone tell me what I'm missing here? Or is there a better way to filter this?

6
  • 2
    Because the starting index is going to be 0, 0-1=-1 -> videos[-1] == undefined Commented Nov 25, 2019 at 23:37
  • Hmm not sure what as a community we can help here, if we cannot get an example of the videos array. Also don't quote me on this but map command only passes upto 2 parameters not 3 video, i, videos Commented Nov 25, 2019 at 23:37
  • Unrelated to your current issue, but you also need to consider what happens when your if block doesn't trigger. If this happens you will get undefined Commented Nov 25, 2019 at 23:39
  • 2
    @AsimPoptani the third parameter for callback is the array Commented Nov 25, 2019 at 23:40
  • Ahhh thanks, @PatrickEvans learn something new everyday Commented Nov 25, 2019 at 23:42

3 Answers 3

2

.map() always returns an array of same length. Functions will return 'undefined' by default. So your array might look like [optionComponent, undefined, undefined, optionComponent] etc.

If you're looking to filter, try using Array.filter() alongside the map:

this.props.videos
.filter(video => video.project.id !== this.props.videos[i - 1].project.id)
.map((video, i, videos) => {
        return (
            <option
                key={video.id}
                value={video.project.id}
            >
              {video.project.projectName}
            </option>
        )
})

Also, "Cannot read property of undefined" might be because index -1 (0 - 1) is undefined

Edit: I'm not sure that callback in the filter function would do the trick though. You could use reduce to use an object to keep track of unique values, then turn that back into an array:

uniqueVideos = Object.values(this.props.videos.reduce((prev, curr) => ({ ...prev, [curr.project.id]: curr }), {}))

Sign up to request clarification or add additional context in comments.

Comments

0

So a map doesn't filter. It iterates over each item and returns something every time. You might be looking for a filter. I used a plain for loop because it might be more understandable in this scenario

function filterVideos(){
    const ids = [];
    const videoDivs = [];
    for(const video of this.props.videos){
        if(ids.includes(video.id)){
            continue
        }
        ids.push(video.id);
        videoDivs.push(
            <option
                key={video.id}
                value={video.project.id}
            >
                {video.project.projectName}
            </option>
        )
    }
    return videoDivs
}

Comments

0

Ok this worked. Thank you Patrick Evans, this should have been obvious to me! I had to add "i > 0" to the if statement.

this.props.videos.map((video, i, videos) => {
    if (i > 0 && video.project.id !== videos[i - 1].project.id) {

        return (
            <option
                key={video.id}
                value={video.project.id}
            >{video.project.projectName}
            </option>
        )
    }
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.