尽管初始化成功,但 Redux 存储仍未定义
Redux store goes undefined despite successful initialization
我有一个控制器组件 "VideoManager",它呈现一个视图组件 "Video"。如果可以通过 props 获得本地视频流,则视图组件会呈现本地视频流,否则它会呈现一个按钮,该按钮通过 getUserMedia 初始化视频流(我已经将 getUserMedia API 调用包装在一个承诺中。查看控制台日志,我看到状态被正确初始化为一个空的不可变映射。但是,当我单击按钮时,状态似乎在承诺完成之前变为 "undefined",因此抛出错误“无法读取 属性 'getIn' of undefined'。大概这是因为状态在 promise 完成之前发生了短暂的变化(尽管我不确定为什么它会进入未定义状态而不是停留在初始状态)。
这是我的控制器组件:
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);
这是我的视图组件:
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>
}
});
我的动作创作者:
export function getLocalVideo(config) {
return {
type: 'GET_LOCAL_VIDEO',
config
};
}
和我的 Reducer:
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;
}
我的假设是正确的吗?如果是这样,我如何防止 'connect' 在承诺实现之前告诉控制器有一个新状态?
编辑
对于后代来说,这是我承诺的 getUserMedia:
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");
}
})
}
您正在这样做:
export default function(state = Map(), action){
switch(action.type) {
case 'GET_LOCAL_VIDEO':
return getLocalVideo(state, action.config);
}
return state;
}
虽然 getLocalVideo 应该 return 新状态,但事实并非如此,这就是状态未定义的原因。你正在修改你的承诺中的状态,这是你不应该做的。相反,尝试在 'getLocalVideo' 函数中执行异步操作,为不同状态调用操作(GET_LOCAL_VIDEO、GET_LOCAL_VIDEO_SUCCESS、GET_LOCAL_VIDEO_FAIL)
像这样的东西应该可以工作(不要忘记调整你的减速器)
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}))
我有一个控制器组件 "VideoManager",它呈现一个视图组件 "Video"。如果可以通过 props 获得本地视频流,则视图组件会呈现本地视频流,否则它会呈现一个按钮,该按钮通过 getUserMedia 初始化视频流(我已经将 getUserMedia API 调用包装在一个承诺中。查看控制台日志,我看到状态被正确初始化为一个空的不可变映射。但是,当我单击按钮时,状态似乎在承诺完成之前变为 "undefined",因此抛出错误“无法读取 属性 'getIn' of undefined'。大概这是因为状态在 promise 完成之前发生了短暂的变化(尽管我不确定为什么它会进入未定义状态而不是停留在初始状态)。
这是我的控制器组件:
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);
这是我的视图组件:
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>
}
});
我的动作创作者:
export function getLocalVideo(config) {
return {
type: 'GET_LOCAL_VIDEO',
config
};
}
和我的 Reducer:
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;
}
我的假设是正确的吗?如果是这样,我如何防止 'connect' 在承诺实现之前告诉控制器有一个新状态?
编辑
对于后代来说,这是我承诺的 getUserMedia:
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");
}
})
}
您正在这样做:
export default function(state = Map(), action){
switch(action.type) {
case 'GET_LOCAL_VIDEO':
return getLocalVideo(state, action.config);
}
return state;
}
虽然 getLocalVideo 应该 return 新状态,但事实并非如此,这就是状态未定义的原因。你正在修改你的承诺中的状态,这是你不应该做的。相反,尝试在 'getLocalVideo' 函数中执行异步操作,为不同状态调用操作(GET_LOCAL_VIDEO、GET_LOCAL_VIDEO_SUCCESS、GET_LOCAL_VIDEO_FAIL)
像这样的东西应该可以工作(不要忘记调整你的减速器)
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}))