1

The this keyword inside the vidsAsHtml mapping function keeps returning undefined.

I read this, and a couple other SO questions about this but their solutions did not solve the problem. I'm already using es6 syntax arrow function for the map, but I've also tried putting in this as a second argument, which didn't solve the issue. Curious if anyone knows why 'this' keyword keeps coming up as undefined here.

 import React, { useState, useEffect } from 'react'
    import axios from 'axios'

    const VideoGrid = (props) => {
      const [videos, setResource] = useState([])

      const fetchVideos = async (amount, category) => {
        const response = await axios.get('https://pixabay.com/api/videos/', {
          params: {
            key: '123456679',
            per_page: amount,
            category: category
          }
        })

        console.log(response)
        const vidsAsHtml = response.data.hits.map(vid => {
          return (
            <div className={`${props.page}--grid-content-wrapper`} key={vid.picture_id}>
              <div className={`${props.page}--grid-video`}>
                <video
                  poster="https://i.imgur.com/Us5ckqm.jpg"
                  onMouseOver={this.play()}
                  onMouseOut={this.pause()}
                  src={`${vid.videos.tiny.url}#t=1`} >
                </video>
              </div>
              <div className={`${props.page}--grid-avatar-placeholder`}></div>
              <div className={`${props.page}--grid-title`}>{vid.tags}</div>
              <div className={`${props.page}--grid-author`}>{vid.user}</div>
              <div className={`${props.page}--grid-views`}>{vid.views} 
                <span className={`${props.page}--grid-date`}> • 6 days ago</span>
              </div>
            </div>
          )
      })
      setResource(vidsAsHtml)
    }

      useEffect(() => {
        fetchVideos(50, 'people')
      }, []) 

        return (
          <main className={`${props.page}--grid-background`}>
            <nav className={`${props.page}--grid-nav`}>

              <button 
                id='followButton' 
                className={`${props.page}--grid-nav-${props.titleOne}`} 
                >{props.titleOne}
              </button>

              <button 
                id='recommendedButton' 
                className={`${props.page}--grid-nav-${props.titleTwo}`} 
                >{props.titleTwo}
              </button>

              <button 
                id='subscriptionsButton' 
                className={`${props.page}--grid-nav-${props.titleThree}`} 
                >{props.titleThree}
              </button>

              <button className={`${props.page}--grid-nav-${props.titleFour}`}>{props.titleFour}</button>
              <button className={`${props.page}--grid-nav-${props.titleFive}`}>{props.titleFive}</button>
              <button className={`${props.page}--grid-nav-follow`}>FOLLOW</button>
            </nav>
            <hr className={`${props.page}--grid-hr-nav-grey`} />
            <hr className={`${props.page}--grid-hr-nav-black`} />        

            <div className={`${props.page}--grid`} style={{marginTop: 'unset'}}>
              {videos}
            </div>
          </main>
        )
      }


    export default VideoGrid
Robert C
  • 756
  • 10
  • 25

2 Answers2

2

Event handler props are expected to be passed a function. Currently you are trying to pass the return values of this.play() and this.pause() as event handlers, which wouldn't work anyway.

Also React doesn't make the element available to the event handler via this, but you can access it via event.target:

<video
  poster="https://i.imgur.com/Us5ckqm.jpg"
  onMouseOver={event => event.target.play()}
  onMouseOut={event => event.target.pause()}
  src={`${vid.videos.tiny.url}#t=1`} >
</video>
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 1
    Ughhhh...I spent a couple hours messing with the ref system, trying querySelectors inside external functions, and a bunch of other stuff despite having a feeling I needed to use event like that from the very beginning. Just didn't know the exact syntax I needed to get the event working and none of the other SO questions I looked at used it. Damn...well it worked like a dream. Thanks. – Robert C Dec 06 '19 at 09:05
0

You can use ref for this,

let vidRef = React.createRef();

You should create function separately,

const playVideo = () => {
   // You can use the play method as normal on your video ref
    vidRef.current.play();
};

const pauseVideo = () => {
   // Pause as well
   vidRef.current.pause();
};

provide ref to video,

<video
  ref = {vidRef}   //Provide ref here
  poster="https://i.imgur.com/Us5ckqm.jpg"
  onMouseOver={() => playVideo()}
  onMouseOut={() => pauseVideo()}
  src={`${vid.videos.tiny.url}#t=1`} >
</video>

Demo

ravibagul91
  • 20,072
  • 5
  • 36
  • 59
  • Gives me vidRef.play() is not a function – Robert C Dec 06 '19 at 07:25
  • Try to print `vidRef` and see if it refers to the correct element. Also, try `vidRef.current.play()` – ravibagul91 Dec 06 '19 at 07:27
  • vidRef gets run immedietely in the console on every video as soon as the DOM loads with a value of undefined. Second option gives cannot read property play of undefined. – Robert C Dec 06 '19 at 07:30
  • Underneath the undefined console logs it gave the error: Uncaught Invariant Violation: Element ref was specified as a string (vidRef) but no owner was set. – Robert C Dec 06 '19 at 07:36
  • I just tried your updated solution. Now the console.log(vidRef) is giving me the video object on mouseover. The problem now is that only sound begins to play when I mouseover, and not the video. I'm using the same video you used in your demo. – Robert C Dec 06 '19 at 08:36
  • It should work. Check the demo, it is working fine. – ravibagul91 Dec 06 '19 at 08:43
  • It's working, just no video is playing. I'm not sure why since I used the same video you used in the demo -- so it can't be an encoding issue...It only shows the thumbnail, then plays sound when I mouseover. – Robert C Dec 06 '19 at 08:49
  • oh, it's really strange. – ravibagul91 Dec 06 '19 at 08:54
  • I moved the video element outside of the mapping statement, down to the bottom return statement, under
    and it worked as normal, just like in the demo. But inside the mapping statement it only plays audio
    – Robert C Dec 06 '19 at 08:58