所以我有一个简单的帖子应用程序。我有一个名为Post.js的组件。会加载一个帖子。
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import Spinner from '../../common/Spinner';
import { getPost } from '../../../actions/postActions';
import PostDetails from './Post-Details';
import CommentForm from './CommentForm';
import CommentFeed from './CommentFeed';
import Navbar from "../../../components/layout/Navbar";
class Post extends Component {
componentDidMount() {
this.props.getPost(this.props.match.params.id);
}
render() {
const { post, loading } = this.props.post;
const { user } = this.props.auth;
let postContent;
if (post === null || loading || Object.keys(post).length === 0) {
postContent = <Spinner />;
} else if (user === null || Object.keys(user).length === 0) {
postContent = (
<div>
<PostDetails post={post} showActions={false}/>
<div className="commentsArea">
<br />
<CommentFeed postId={post._id} comments={post.comments} />
</div>
</div>
)
} else {
postContent = (
<div>
<PostDetails post={post} showActions={false}/>
<div className="commentsArea">
<CommentForm postId={post._id} />
<CommentFeed postId={post._id} comments={post.comments} />
</div>
</div>
);
}
return (
<div className="postSingle">
<Navbar />
<div className="container">
<div className="row">
<div className="col-md-12">
{postContent}
</div>
</div>
</div>
</div>
);
}
}
Post.propTypes = {
getPost: PropTypes.func.isRequired,
post: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
post: state.post,
auth: state.auth
});
export default connect(mapStateToProps, { getPost })(Post);
该组件只有几个子组件,其中PostDetails.js可显示帖子的实际详细信息,例如图片,标题正文,作者和标签。
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import classnames from "classnames";
import Related from "./RelatedPosts"
import { Link } from "react-router-dom";
import { deletePost, addLike, removeLike } from "../../../actions/postActions";
import Moment from "react-moment";
import Truncate from "react-truncate";
export class PostItem extends Component {
onDeleteClick(id) {
this.props.deletePost(id);
}
onLikeClick(id) {
this.props.addLike(id);
}
onUnlikeClick(id) {
this.props.removeLike(id);
}
findUserLike(likes) {
const { auth } = this.props;
if (likes.filter(like => like.user === auth.user.id).length > 0) {
return true;
} else {
return false;
}
}
render() {
const { post, auth, showActions } = this.props;
const { isAuthenticated, user } = this.props.auth;
const tags = post.tags.map((tag, index) => (
<div key={index} className="p-3">
<i className="fa fa-check" /> {tag}
</div>
));
const editbtn = (
<Link to={{
pathname:'/editpost',
postProps:{
id:post._id
}
}}>
Edit
</Link>
)
return (
<React.Fragment>
<div className="row">
<div className="card card-body col-md-8">
<div className="row">
<div className="cardHeaderImage col-md-12 ">
{post.headerimage === "" ? (
" "
) : (
<img
src={post.headerimage}
className="card-img-top"
alt="..."
/>
)}
</div>
<div className="postHeadline col-md-12 ">
<h3>
<span className="headlineTitle">{post.headline}</span>
<span className="commentsCount">
{post.comments.length} Comments
</span>
</h3>
</div>
</div>
<div className="postAuthor row">
<h6>By {post.user.name}</h6>
{/* <img src={post.avatar} alt=""/> */}
<h6>
Posted <Moment format="MM/DD/YYYY">{post.date}</Moment>
</h6>
{isAuthenticated && user.name === post.user.name ? editbtn : ""}
</div>
<div className="row">
<div className="postText col-md-12">
<p className="card-text">{post.text}</p>
<br />
<h3>Tags</h3>
<p style={{ display: "flex" }}>{tags}</p>
{showActions ? (
<span className="profileActions">
<button
onClick={this.onLikeClick.bind(this, post._id)}
type="button"
className="btn btn-concord mr-1"
>
<i
className={classnames("fas fa-thumbs-up", {
"text-info": this.findUserLike(post.likes),
})}
/>
<span className="badge badge-concord">
{post.likes.length}
</span>
</button>
<button
onClick={this.onUnlikeClick.bind(this, post._id)}
type="button"
className="btn btn-concord mr-1"
>
<i className="text-secondary fas fa-thumbs-down" />
</button>
<Link to={`/post/${post._id}`} className="btn btn-sole mr-1">
Read More
</Link>
{post.user._id === auth.user.id ||
post.user === auth.user.id ? (
<button
onClick={this.onDeleteClick.bind(this, post._id)}
type="button"
className="btn btn-danger mr-1"
>
<i className="fas fa-times" />
</button>
) : null}
</span>
) : null}
</div>
</div>
</div>
<Related tags={post.tags} postId={post} />
</div>
</React.Fragment>
);
}
}
PostItem.defaultProps = {
showActions: true
};
PostItem.propTypes = {
deletePost: PropTypes.func.isRequired,
addLike: PropTypes.func.isRequired,
removeLike: PropTypes.func.isRequired,
post: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
profile: state.profile,
auth: state.auth
});
export default connect(
mapStateToProps,
{ deletePost, addLike, removeLike }
)(PostItem);
并且PostDetails具有子组件(RelatedPosts.js),该子组件呈现与当前加载的帖子相关的帖子的详细信息。我使用当前帖子的帖子标签,并在后端查询具有匹配标签的其他帖子。如果找到任何相关文章的预览详细信息,将显示在RelatedPosts.js中。在PostDetail.js组件中显示为侧边栏
import React, { Component } from 'react'
import { connect } from 'react-redux';
import { getRelatedPosts } from '../../../actions/postActions';
import Truncate from "react-truncate";
import { Link } from "react-router-dom";
export class RelatedPosts extends Component {
componentDidMount() {
const { tags, postId } = this.props;
this.props.getRelatedPosts(tags);
}
render() {
const { tags, postId } = this.props;
const { posts } = this.props.post;
let related = posts.map(post => {
return (
<div className="card" style={{ marginBottom: "20px" }}>
<img className="card-img-top" src={post.headerimage} alt="" />
<div className="card-body">
<h4 className="card-title">{post.headline}</h4>
<p className="card-text">
<Truncate lines={2} ellipsis={<span>...</span>}>
{post.text}
</Truncate>
</p>
<Link to={`/post/${post._id}`} className="btn btn-sole mr-1">
Read More
</Link>
</div>
</div>
);
});
return (
<div className="col-md-3 offset-1 card related">
<h3>Related Posts</h3>
<ul>
{related}
</ul>
</div>
)
}
}
const mapStateToProps = state => ({
post: state.post,
auth: state.auth
});
export default connect(mapStateToProps, { getRelatedPosts })(RelatedPosts);
希望我对上述代码结构的解释是合理的。以上所有这些都很好。但是,当我单击相关帖子之一中的链接时。
来自RelatedPosts.js
<Link to={`/post/${post._id}`} className="btn btn-sole mr-1">
Read More
</Link>
链接URL会适当更改,但是不会重新呈现任何内容。屏幕上仍显示相同的帖子。但是,当我刷新页面时,它将随后呈现我单击的相关帖子。我不知道为什么会这样。
这是来自我的App.js组件的相关代码,其中包含我的路由器
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import jwt_decode from 'jwt-decode';
import setAuthToken from './utils/setAuthToken';
import { setCurrentUser, logoutUser } from './actions/authActions';
import { clearCurrentProfile } from './actions/profileActions';
import { Provider } from 'react-redux';
import store from './store';
import ScrollToTop from './ScrollToTop'
import PrivateRoute from './components/common/PrivateRoute';
import AuthorRoute from './components/common/AuthorRoute';
import Posts from './components/posts/all-users-posts/AllPosts';
import Post from './components/posts/post-single/Post';
import CreatePost from './components/posts/post-creation/CreatePost';
import EditPost from './components/posts/post-creation/EditPost';
class App extends Component {
render() {
return (
<Provider store={store}>
<Router>
<ScrollToTop>
<React.Fragment>
<Route exact path="/register" component={Register} />
<Route exact path="/login" component={Login} />
<Route exact path="/profiles" component={Profiles} />
<Route exact path="/profile/:handle" component={Profile} />
<Route exact path="/post/:id" component={Post} />
<Route exact path="/allposts" component={Posts} />
<Route exact path="/editpost/" component={EditPost} />
</React.Fragment>
</ScrollToTop>
</Router>
</Provider>
);
}
}
export default App;
这不是我的React的全部代码,而是与我的问题相关的代码。我唯一能想到的是,即使URL发生更改,当我单击链接时,它仍然使用相同的组件:
<Route exact path="/post/:id" component={Post} />
也许这至少是问题的一部分。
答案 0 :(得分:1)
这是一个长期问题,混乱的组件命名。我懒于阅读所有内容,但我认为我的答案是正确的。 那是因为:
'/post/:id'
与 Post
组件Post
组件因此,当您单击它(位于 Post 组件中)时,React不会再次卸载并重新安装Post组件。只是 更新 。 因此它将调用更新生命周期方法,例如: Post
的 shouldComponentUpdate,render,componentDidUpdate ...因此该解决方案使用 componentDidUpdate 方法获取新postId 并再次获取Post数据