如何使用window.history或React Router跟踪URL更改。重新呈现网址更改后的子组件?

时间:2020-06-14 19:58:14

标签: javascript reactjs react-router browser-history

TLDR:当路径的参数相同时,如何基于窗口的历史记录/位置来重新呈现子级而又不重新呈现父级?感谢您的帮助,我已经在此方面停留了一段时间几天以来,我希望能够了解我在做什么错。谢谢!

我在ReactJS应用程序中使用React-router-dom v5。我有2条路径,如下所示:

<Route exact path="/users/:handle" component={user} />
<Route exact path="/users/:handle/post/:postId" component={user} />

我试图做到这一点,所以当单击通知菜单项时,它将通过反应路由器dom链接(包括在下面)链接到第二条路径。我不希望在初始安装后重新渲染整个用户组件。

<Link key={not.createdAt} to={`/users/${not.recipient}/post/${not.postId}`}>Text here</Link>

这将提示用户组件安装,并且帖子将显示为弹出窗口。我目前正在通过用户组件上的ComponentDidUpdate阅读参数更新,相关代码如下所示。 但是,仅在参数更改时读取。 我想这样做,以便当用户打开通知,关闭通知并以相同的路径打开相同的通知时,它仍将重新呈现帖子组件。的路径如下:< / p>

open notif -> /users/:handle/post/:postId, setState of postId
close popup -> /users/:handle
open same notif -> /users/:handle/post/:postId, url changes but post component does not rerender

我对如何实现这一目标感到迷茫。我已经阅读了很多SO线程,但对我来说没有任何用处,找不到类似问题的人。 我曾尝试,将withRouter高阶组件用于此,但是每次按下this.props.location时,这都会重新呈现整个用户组件。我只希望post组件在url更改时重新加载。我也尝试过在post组件上使用key来仅在postIdParams状态更新或位置更新但没有运气时重新加载帖子。当弹出窗口关闭并且URL更改为/ users /:handle时,没有任何调用。我认为这是因为我正在使用window.history而不是this.props.location来更改路径。

相关代码: 用户组件(不想重新呈现):

class user extends Component {
state = {
postIdParam: null,
openTimeline: true,
openLikes: false
};

componentDidMount() {
 const postId = this.props.match.params.postId;
 if (postId) this.setState({ postIdParam: postId });
}
componentDidUpdate(prevProps) {
// if postId params change, update state
if (this.props.match.params.postId !== prevProps.match.params.postId) {
  const postId = this.props.match.params.postId;
  this.setState({ postIdParam: postId });
}

// renders and passes postIdParam state: <ProfileTimeline profile={profile} postIdParam={postIdParam} 
loading={loading} posts={posts}

我要在url更改后重新呈现的组件呈现帖子:

export class ProfileTimeline extends Component {
state = {
key: null
};
componentDidMount() {
const key = `${this.props.location.pathname}${this.props.location.search}`
if (key) this.setState({ key: key });
console.log("Mount: " + key);
}
componentDidUpdate(prevProps) {
if (this.props.location.pathname !== prevProps.location.pathname) {
  const key = `${this.props.location.pathname}${this.props.location.search}`
  this.setState({ key: key });
  console.log("Update: " + key);
}
}
render() {
    const {
        classes,
        loading,
        posts,
        profile: {
            handle,
            bio,
            location,
            website,
            followingCount,
            followersCount,
            createdAt
        },
        postIdParam
      } = this.props;

  const postsMarkup = posts.map((post) => {
      if (post.postId !== postIdParam)
        return <Post key={post.postId} post={post} />;
      else return <Post key={post.postId} post={post} profileHandle={handle} openDialog />; // opens 
      post popup
    })
  );
    return(
    <section className={classes.timeline} key={this.state.key}></section>

发布组件功能,用于管理弹出窗口和推送状态的打开和关闭:

handleOpen = () => {
let oldPath = window.location.pathname;

const { userHandle, postId, profileHandle } = this.props;
const newPath = `/users/${userHandle}/post/${postId}`;
const profilePath = `/users/${profileHandle}/post/${postId}`;

if (oldPath === newPath || oldPath === profilePath) oldPath = `/users/${profileHandle}`;

window.history.pushState(null, null, newPath);

this.setState({ open: true, oldPath, newPath });
this.props.getPost(this.props.postId);
};
handleClose = () => {
window.history.pushState(null, null, this.state.oldPath);
this.setState({ open: false });
this.props.clearErrors();
};

0 个答案:

没有答案