Uncaught TypeError: невозможно прочитать свойство id для undefined / window.location.reload () - PullRequest
1 голос
/ 14 июля 2020

Я создаю форму комментария, которая позволит разместить комментарий под видео. Это вызывает ошибку идентификатора внутри конструктора, которая исчезает при перезагрузке страницы. OwnProps выглядит как пустой объект, иначе я бы использовал его для получения идентификатора видео. Мое решение с 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 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 { 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';
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;

введите описание изображения здесь

1 Ответ

1 голос
/ 14 июля 2020

Единственная проблема здесь в том, что компонент Comment пытается выполнить рендеринг до загрузки видео. Я предполагаю, что вы загружаете видео, а это означает, что если его нет даже на мгновение, будет выдана эта ошибка.

Решением этого является условный рендеринг Comment, когда вы знаете, что видео существует . Вы можете сделать это либо в родительском, либо в дочернем.

Удалите это из mapStateToProps:

    if (video) {
        return { 
            video,
        }
    } else {
        window.location.reload()
    }

И убедитесь, что видео существует перед рендерингом Comment

Возможное решение в родительском элементе:

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

Дополнительно

Вы можете отобразить какой-то круговой индикатор выполнения вместо нуля

Возможное решение в дочернем элементе

Удалить video_id из состояния, так как он в любом случае не должен обновляться и не должен быть состоянием. Затем проверьте существование перед возвратом следующим образом:

if (!video) return <div />
return (
  // Your Comment jsx
)

Опять же, вы можете отобразить какой-то индикатор прогресса вместо div, если хотите.

Почему это работает

Если видео в этот момент не существует, оно вернет div и не будет sh. Как только видео существует, оно будет повторно отрисовано и теперь загрузит компонент комментария вместо div. Обычно это происходит так быстро, что вы даже не заметите.

...