2015-12-30 1 views
1

J'ai un composant de contrôleur "VideoManager" qui rend un composant de vue "Vidéo". Le composant view rend un flux vidéo local s'il est disponible via les accessoires, sinon il affiche un bouton qui initialise un flux vidéo via getUserMedia (j'ai encapsulé l'appel de l'API getUserMedia dans une promesse. est correctement initialisé comme une carte immuable vide Cependant, quand je clique sur le bouton, il semble que l'état devienne "indéfini" avant que la promesse se termine, et jette donc une erreur "Impossible de lire la propriété 'getIn' de indéfini. les changements d'état brièvement avant la promesse complète (bien que je ne sais pas pourquoi il irait undefined plutôt que de rester dans son état initial)La mémoire Redux n'est pas définie malgré une initialisation réussie

Voici mon composant contrôleur:.

import React from 'react'; 
import {connect} from 'react-redux'; 
import Video from './Video'; 
import bowser from 'bowser'; 
import * as actionCreators from '../action_creators'; 

export const VideoManager = React.createClass({ 
    render: function() { 
    return <div> 
     <div>This is the VideoManager component.</div> 
     <div>{bowser.chrome && bowser.version > 34 ? "Welcome!" : "Sorry, we only support Chrome version 34 and above"}</div> 
     <Video {...this.props}/> 
    </div> 
    } 
}); 

function mapStateToProps(state) { 
    return{ 
    localStreamURL: state.getIn(['localStreamInfo', 'localStreamURL']) 
    }; 
} 

export const VideoManagerContainer = connect(mapStateToProps, actionCreators)(VideoManager); 

Voici mon composant Vue:

import React from 'react'; 

export default React.createClass({ 

    render: function() { 
    const videoAndAudio = {audio: false, video: true}; 
    return <div> 
     <div>This is the Video component.</div> 
     {this.props.localStreamURL ? <video id="localVideo" src={this.props.localStreamURL}></video> : <button onClick={() => this.props.getLocalVideo(videoAndAudio)}>Get Local Video</button>} 
    </div> 
    } 
}); 

Mes créateurs d'action:

export function getLocalVideo(config) { 
    return { 
    type: 'GET_LOCAL_VIDEO', 
    config 
    }; 
} 

et mon Réducteur:

import {List, Map} from 'immutable'; 
import {createLocalStream} from './utils/webrtc_utils'; 

function getLocalVideo(state, config){ 
    createLocalStream(config).then(
    function(stream){  
     return state.set('localStreamInfo', Map({ 
      localStream: stream, 
      localStreamURL: URL.createObjectURL(stream) 
     })); 
}, function(err){ 
     console.log("Stream collection failed: ", err); 
}); 
} 

export default function(state = Map(), action){ 
    switch(action.type) { 
     case 'GET_LOCAL_VIDEO': 
      return getLocalVideo(state, action.config); 
    } 
    return state; 
} 

Ai-je raison dans mon hypothèse que la promesse est lorsque cela est avoir déraillé? Si c'est le cas, comment empêcher 'connect' de dire au contrôleur qu'il y a un nouvel état avant que la promesse soit remplie?

EDIT
pour la postérité ici est mon getUserMedia promesse enveloppée:

export function createLocalStream(callConfig){ 
    return new Promise(function(resolve, reject){ 
     navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia; 

     if (navigator.getUserMedia) { 
      navigator.getUserMedia(callConfig, 
       function(stream) { 
       resolve(stream);     
       }, 
       function(err) { 
       reject("The following error occured: " + err.name); 
       } 
      ); 
     } else { 
      reject("getUserMedia not supported"); 
     } 
    }) 
} 

Répondre

1

que vous faites ceci:

export default function(state = Map(), action){ 
    switch(action.type) { 
     case 'GET_LOCAL_VIDEO': 
      return getLocalVideo(state, action.config); 
    } 
    return state; 
} 

Alors que getLocalVideo devrait retourner le nouvel état, il n'est pas, ce qui explique pourquoi l'état n'est pas défini. Vous modifiez l'état dans votre promesse, ce que vous ne devriez pas faire. Au contraire, essayez de faire les choses async au sein de votre fonction « getLocalVideo », appelant actions pour vos différents états (GET_LOCAL_VIDEO, GET_LOCAL_VIDEO_SUCCESS, GET_LOCAL_VIDEO_FAIL)

Quelque chose comme cela devrait fonctionner (ne pas oublier d'adapter votre réducteur)

export function getLocalVideo(config) { 
    dispatch({type: 'GET_LOCAL_VIDEO', config}); 
    createLocalStream(config).then((stream)=> 
     dispatch({ 
      type: 'GET_LOCAL_VIDEO_SUCCESS', 
      localStreamInfo: Map({ 
       localStream: stream, 
       localStreamURL: URL.createObjectURL(stream) 
      }) 
     }) 
    }).catch((error)=>dispatch({type:'GET_LOCAL_VIDEO_FAIL', error})) 
+0

merci quambo. devrais-je déplacer cette fonction getLocalVideo vers mon fichier de créateur d'action ou devrait-il rester dans le réducteur? –

+0

Vous avez plusieurs options. 1. Vous pouvez le mettre dans le fichier créateur de l'action (ce que la plupart des gens feraient probablement). 2. Vous pouvez le mettre dans son propre fichier (comme /lib/local-stream.js) et l'importer dans le créateur de l'action (ce qui pourrait être considéré comme l'option la plus propre). 3. Vous pouvez mettre tout (types d'actions, actions et réducteurs) dans un fichier comme décrit ici: https://github.com/erikras/ducks-modular-redux (qui pourrait être l'option la plus confortable) – quambo