简体   繁体   中英

index isn't working as expected in React array.Map function

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?

.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 }), {}))

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
}

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>
        )
    }
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM