diff --git a/src/lib/vm-listener-hoc.jsx b/src/lib/vm-listener-hoc.jsx
index ad6a9f9126336c36ed4d4adcb9dca573dab3e1cb..5e18cdaf1ec42a76509fc3ab05ab3994e5b77c66 100644
--- a/src/lib/vm-listener-hoc.jsx
+++ b/src/lib/vm-listener-hoc.jsx
@@ -23,7 +23,8 @@ const vmListenerHOC = function (WrappedComponent) {
             super(props);
             bindAll(this, [
                 'handleKeyDown',
-                'handleKeyUp'
+                'handleKeyUp',
+                'handleTargetsUpdate'
             ]);
             // We have to start listening to the vm here rather than in
             // componentDidMount because the HOC mounts the wrapped component,
@@ -31,7 +32,7 @@ const vmListenerHOC = function (WrappedComponent) {
             // mounts.
             // If the wrapped component uses the vm in componentDidMount, then
             // we need to start listening before mounting the wrapped component.
-            this.props.vm.on('targetsUpdate', this.props.onTargetsUpdate);
+            this.props.vm.on('targetsUpdate', this.handleTargetsUpdate);
             this.props.vm.on('MONITORS_UPDATE', this.props.onMonitorsUpdate);
             this.props.vm.on('BLOCK_DRAG_UPDATE', this.props.onBlockDragUpdate);
             this.props.vm.on('TURBO_MODE_ON', this.props.onTurboModeOn);
@@ -49,9 +50,15 @@ const vmListenerHOC = function (WrappedComponent) {
             }
             this.props.vm.postIOData('userData', {username: this.props.username});
         }
-        componentWillReceiveProps (newProps) {
-            if (newProps.username !== this.props.username) {
-                this.props.vm.postIOData('userData', {username: newProps.username});
+        componentDidUpdate (prevProps) {
+            if (prevProps.username !== this.props.username) {
+                this.props.vm.postIOData('userData', {username: this.props.username});
+            }
+
+            // Re-request a targets update when the shouldEmitTargetsUpdate state changes to true
+            // i.e. when the editor transitions out of fullscreen/player only modes
+            if (this.props.shouldEmitTargetsUpdate && !prevProps.shouldEmitTargetsUpdate) {
+                this.props.vm.emitTargetsUpdate();
             }
         }
         componentWillUnmount () {
@@ -61,6 +68,11 @@ const vmListenerHOC = function (WrappedComponent) {
                 document.removeEventListener('keyup', this.handleKeyUp);
             }
         }
+        handleTargetsUpdate (data) {
+            if (this.props.shouldEmitTargetsUpdate) {
+                this.props.onTargetsUpdate(data);
+            }
+        }
         handleKeyDown (e) {
             // Don't capture keys intended for Blockly inputs.
             if (e.target !== document && e.target !== document.body) return;
@@ -89,6 +101,7 @@ const vmListenerHOC = function (WrappedComponent) {
             const {
                 /* eslint-disable no-unused-vars */
                 attachKeyboardEvents,
+                shouldEmitTargetsUpdate,
                 username,
                 onBlockDragUpdate,
                 onKeyDown,
@@ -120,6 +133,7 @@ const vmListenerHOC = function (WrappedComponent) {
         onTargetsUpdate: PropTypes.func.isRequired,
         onTurboModeOff: PropTypes.func.isRequired,
         onTurboModeOn: PropTypes.func.isRequired,
+        shouldEmitTargetsUpdate: PropTypes.bool,
         username: PropTypes.string,
         vm: PropTypes.instanceOf(VM).isRequired
     };
@@ -127,6 +141,8 @@ const vmListenerHOC = function (WrappedComponent) {
         attachKeyboardEvents: true
     };
     const mapStateToProps = state => ({
+        // Do not emit target updates in fullscreen or player only mode
+        shouldEmitTargetsUpdate: !state.scratchGui.mode.isFullScreen && !state.scratchGui.mode.isPlayerOnly,
         vm: state.scratchGui.vm,
         username: state.session && state.session.session && state.session.session.user ?
             state.session.session.user.username : ''