Javascript 未捕获类型错误:无法读取属性';id';未定义/window.location.reload()的

Javascript 未捕获类型错误:无法读取属性';id';未定义/window.location.reload()的,javascript,react-redux,Javascript,React Redux,我正在创建一个评论表单,允许在视频下方发布评论。它在构造函数中抛出id错误,该错误在页面重新加载时消失。ownProps显示为空对象,否则我会使用它来获取视频id。我使用window.location.reload()的解决方案是蹩脚的。有人知道更好的吗 注释容器 import React from 'react'; import { connect } from 'react-redux'; import Comment from './comment'; import { fetchComm

我正在创建一个评论表单,允许在视频下方发布评论。它在构造函数中抛出id错误,该错误在页面重新加载时消失。ownProps显示为空对象,否则我会使用它来获取视频id。我使用window.location.reload()的解决方案是蹩脚的。有人知道更好的吗

注释容器

import React from 'react';
import { connect } from 'react-redux';
import Comment from './comment';
import { fetchComments, updateComment, createComment } from '../../util/comment_api_util';

const mSTP = state => {
    const id = Object.keys(state.entities.videos);
    const video = state.entities.videos[id];
    
    if (video) {
        return { 
            video,
        }
    } else {
        window.location.reload()
    }
}

const mDTP = dispatch => {
    return {
        fetchComments: () => dispatch(fetchComments()),
        fetchComment: commentId => dispatch(fetchComment(commentId)),
        createComment: comment => dispatch(createComment(comment)),
        updateComment: comment => dispatch(updateComment(comment)),
        deleteComment: commentId => dispatch(deleteComment(commentId))
    }
}

export default connect(mSTP, mDTP)(Comment)
import { connect } from 'react-redux';
import Play from './play';
import { fetchVideo } from '../../actions/video_actions';
import { fetchUsers } from '../../actions/user_actons';
import { fetchComments } from '../../actions/comment_actions';

const mSTP = (state, ownProps) => {
    const users = Object.values(state.entities.users)
    return {
        video: state.entities.videos[ownProps.match.params.id],
        users
    }
};

const mDTP = dispatch => ({
    fetchComments: () => dispatch(fetchComments()),
    fetchVideo: videoId => dispatch(fetchVideo(videoId)),
    fetchUsers: () => dispatch(fetchUsers()),
});


export default connect(mSTP, mDTP)(Play);
注释组件

import React from 'react';

class Comment extends React.Component {

    constructor(props) {
        
        super(props)
        this.state = {
            body: "",
            // video_id: this.props.video.id,
            comment_errors: null,
        }
        this.update = this.update.bind(this)
        this.handleSubmit = this.handleSubmit.bind(this)
    }

    update() {
        return e => this.setState({ body: e.target.value })
    }

    handleSubmit(e) {
        e.preventDefault();
        const formData = new FormData();
        formData.append('comment[body]', this.state.body);
        formData.append('comment[video_id]', this.state.video_id);
        $.ajax({
            url: '/api/comments',
            method: 'POST',
            data: formData,
            contentType: false,
            processData: false
        }).then(
            (response) => {
                this.setState(
                    { comment_errors: response.responseJSON },
                )
            }
        ).then(() => {
            this.setState(
                { body: "", video_id: "", comment_errors: null }
            )
        });
    }


    render() {
        // if (!this.props.video) return <div />
        return ( 
            <div>
                <form onSubmit={this.handleSubmit}>
                    <label>
                        <textarea 
                            type="body" 
                            placeholder="Add a comment"
                            value={this.state.body}
                            onChange={this.update()}
                            className="comment-body"/>
                    </label>
                    <button type="submit">Add comment</button>                    
                </form>
            </div>
        )
    }
}

export default Comment;
import React from 'react';
import Comment from '../comment/comment_container'



class Play extends React.Component {

    constructor(props) {
        super(props);
    }
    
    dateCreated(date) {
        const dateCreated = new Date(date)
        return dateCreated.toLocaleDateString();
    }

    componentDidMount() {
        this.props.fetchUsers();
        this.props.fetchComments();
        this.props.fetchVideo(this.props.match.params.id).then(() => {
            const video = document.querySelector('.video-player');
            video.muted = !video.muted;
            video.play()
        });
    }
    
    render() {
        if (!this.props.video) { return null }
        console.log(this.props)
        const users = this.props.users;
        const owner = users.filter(user => user.id === this.props.video.owner_id)[0]
        return (
            <div id="video-container">
                <video
                    className="video-player"
                    controls="controls"
                    src={this.props.video.video_url}
                    autoPlay="autoplay"
                    muted 
                >
                </video>
                <div id="play-info">
                    <h1 className="play-title">{this.props.video.video_title}</h1>
                    <h2 className="play-date">{this.dateCreated(this.props.video.created_at)}</h2>
                    <h2 className="owner-name">{owner.username}</h2> 
                    <h2 className="play-description">{this.props.video.video_description}</h2>
                </div>
                <Comment />
                <div className="home-footer">
                    <h2 className="home-footer-1">@2020</h2>
                    <h2 className="home-footer-2">
                        Made with
                            <svg viewBox="0 0 20 20" className="_3Weix"><path d="M10 18a1.23 1.23 0 01-.8-.4 14.25 14.25 0 00-4.4-3.7C2.5 12.3 0 10.7 0 7.5a5.52 5.52 0 011.6-3.9A5.73 5.73 0 016 2a5.25 5.25 0 014 1.9A5.85 5.85 0 0114 2c2.9 0 6 2.2 6 5.5s-2.5 4.8-4.8 6.4a15.51 15.51 0 00-4.4 3.7 1.23 1.23 0 01-.8.4z" fill="rgb(255,0,0)"></path></svg>
                            NYC
                        </h2>
                </div>
            </div>
        );
    }

}

export default Play;
播放组件

import React from 'react';

class Comment extends React.Component {

    constructor(props) {
        
        super(props)
        this.state = {
            body: "",
            // video_id: this.props.video.id,
            comment_errors: null,
        }
        this.update = this.update.bind(this)
        this.handleSubmit = this.handleSubmit.bind(this)
    }

    update() {
        return e => this.setState({ body: e.target.value })
    }

    handleSubmit(e) {
        e.preventDefault();
        const formData = new FormData();
        formData.append('comment[body]', this.state.body);
        formData.append('comment[video_id]', this.state.video_id);
        $.ajax({
            url: '/api/comments',
            method: 'POST',
            data: formData,
            contentType: false,
            processData: false
        }).then(
            (response) => {
                this.setState(
                    { comment_errors: response.responseJSON },
                )
            }
        ).then(() => {
            this.setState(
                { body: "", video_id: "", comment_errors: null }
            )
        });
    }


    render() {
        // if (!this.props.video) return <div />
        return ( 
            <div>
                <form onSubmit={this.handleSubmit}>
                    <label>
                        <textarea 
                            type="body" 
                            placeholder="Add a comment"
                            value={this.state.body}
                            onChange={this.update()}
                            className="comment-body"/>
                    </label>
                    <button type="submit">Add comment</button>                    
                </form>
            </div>
        )
    }
}

export default Comment;
import React from 'react';
import Comment from '../comment/comment_container'



class Play extends React.Component {

    constructor(props) {
        super(props);
    }
    
    dateCreated(date) {
        const dateCreated = new Date(date)
        return dateCreated.toLocaleDateString();
    }

    componentDidMount() {
        this.props.fetchUsers();
        this.props.fetchComments();
        this.props.fetchVideo(this.props.match.params.id).then(() => {
            const video = document.querySelector('.video-player');
            video.muted = !video.muted;
            video.play()
        });
    }
    
    render() {
        if (!this.props.video) { return null }
        console.log(this.props)
        const users = this.props.users;
        const owner = users.filter(user => user.id === this.props.video.owner_id)[0]
        return (
            <div id="video-container">
                <video
                    className="video-player"
                    controls="controls"
                    src={this.props.video.video_url}
                    autoPlay="autoplay"
                    muted 
                >
                </video>
                <div id="play-info">
                    <h1 className="play-title">{this.props.video.video_title}</h1>
                    <h2 className="play-date">{this.dateCreated(this.props.video.created_at)}</h2>
                    <h2 className="owner-name">{owner.username}</h2> 
                    <h2 className="play-description">{this.props.video.video_description}</h2>
                </div>
                <Comment />
                <div className="home-footer">
                    <h2 className="home-footer-1">@2020</h2>
                    <h2 className="home-footer-2">
                        Made with
                            <svg viewBox="0 0 20 20" className="_3Weix"><path d="M10 18a1.23 1.23 0 01-.8-.4 14.25 14.25 0 00-4.4-3.7C2.5 12.3 0 10.7 0 7.5a5.52 5.52 0 011.6-3.9A5.73 5.73 0 016 2a5.25 5.25 0 014 1.9A5.85 5.85 0 0114 2c2.9 0 6 2.2 6 5.5s-2.5 4.8-4.8 6.4a15.51 15.51 0 00-4.4 3.7 1.23 1.23 0 01-.8.4z" fill="rgb(255,0,0)"></path></svg>
                            NYC
                        </h2>
                </div>
            </div>
        );
    }

}

export default Play;
从“React”导入React;
从“../Comment/Comment\u容器”导入注释
类播放扩展了React.Component{
建造师(道具){
超级(道具);
}
创建日期(日期){
const dateCreated=新日期(日期)
return dateCreated.toLocaleDateString();
}
componentDidMount(){
this.props.fetchUsers();
this.props.fetchComments();
this.props.fetchVideo(this.props.match.params.id)。然后(()=>{
const video=document.querySelector(“.video player”);
video.muted=!video.muted;
视频播放()
});
}
render(){
如果(!this.props.video){return null}
console.log(this.props)
const users=this.props.users;
const owner=users.filter(user=>user.id==this.props.video.owner\u id)[0]
返回(
{this.props.video.video_title}
{this.dateCreated(this.props.video.created_at)}
{owner.username}
{this.props.video.video_description}
@2020
用
纽约市
);
}
}
导出默认播放;

这里唯一的问题是
注释组件试图在加载视频之前进行渲染。我假设您正在获取视频,这意味着,如果它不存在,即使是一瞬间,这个错误将抛出

解决方法是在知道视频存在时有条件地呈现
注释
。您可以在父级或子级中执行此操作

从MapStateTops中删除此选项:

    if (video) {
        return { 
            video,
        }
    } else {
        window.location.reload()
    }
并在呈现
注释之前检查视频是否存在

父级中可能的解决方案:

{video && video.id ? <Comment video={video} /> : null}
{video&&video.id?:null}
另外

您可以呈现某种循环进度指示器,而不是null

儿童中可能的解决方案

从状态中删除视频id,因为它无论如何都不应该更新,也不需要是状态。然后在返回前检查是否存在,如下所示:

if (!video) return <div />
return (
  // Your Comment jsx
)
if(!video)返回
返回(
//您对jsx的评论
)
同样,如果需要,可以呈现某种进度指示器而不是div

为什么它有效


当视频在那个瞬间不存在时,它将返回div并且不会崩溃。一旦视频存在,它将重新渲染,现在将加载注释组件而不是div。通常情况下,它会发生得很快,以至于您不会注意到。

因此,在prop参数中未定义video属性。如何在子端执行此操作?如果此解决方案不起作用,请尝试发布更多代码,以便我可以更好地了解它是什么继续。根据你的要求,这似乎是解决办法。我添加了注释和播放组件的代码。Play已出现视频状态。我试了好几件事,但还是出错了。我还需要在注释创建的构造函数中使用video_id将注释构造函数中的video_id初始化为道具,但我不知道这些道具来自何处。你在游戏中调用
,没有任何道具,我在评论组件中没有看到任何MapStateTrops。你完全正确,我只需要将道具从父对象传递给子对象。非常感谢。