Javascript 未捕获类型错误:无法读取属性';id';未定义/window.location.reload()的
我正在创建一个评论表单,允许在视频下方发布评论。它在构造函数中抛出id错误,该错误在页面重新加载时消失。ownProps显示为空对象,否则我会使用它来获取视频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
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。你完全正确,我只需要将道具从父对象传递给子对象。非常感谢。