Skip pushing a new history if the new page hash is the same as the current one
diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx
index bf92f0aa5d26..b22938425876 100644
--- a/frontend/src/App.test.tsx
+++ b/frontend/src/App.test.tsx
@@ -929,6 +929,44 @@ describe("App.handleNewSession", () => {
         "/foo/page2"
       )
     })
+
+    it("doesn't push a duplicated history when rerunning", () => {
+      const instance = wrapper.instance() as App
+      const newSessionJson = cloneDeep(NEW_SESSION_JSON)
+      newSessionJson.appPages = [
+        { pageScriptHash: "toppage_hash", pageName: "streamlit_app" },
+        { pageScriptHash: "subpage_hash", pageName: "page2" },
+      ]
+
+      // When running the top page first, a new history for the page is pushed.
+      instance.handleNewSession(
+        new NewSession({ ...newSessionJson, pageScriptHash: "toppage_hash" })
+      )
+      expect(window.history.pushState).toHaveBeenLastCalledWith({}, "", "/")
+      // @ts-ignore
+      window.history.pushState.mockClear()
+
+      // When running the same, e.g. clicking the "rerun" button,
+      // the history is not pushed again.
+      instance.handleNewSession(
+        new NewSession({ ...newSessionJson, pageScriptHash: "toppage_hash" })
+      )
+      expect(window.history.pushState).not.toHaveBeenCalled()
+      // @ts-ignore
+      window.history.pushState.mockClear()
+
+      // When accessing a different page, a new history for that page is pushed.
+      instance.handleNewSession(
+        new NewSession({ ...newSessionJson, pageScriptHash: "subpage_hash" })
+      )
+      expect(window.history.pushState).toHaveBeenLastCalledWith(
+        {},
+        "",
+        "/page2"
+      )
+      // @ts-ignore
+      window.history.pushState.mockClear()
+    })
   })
 })
 
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index a775de769c19..3c0456bc09bd 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -726,7 +726,7 @@ export class App extends PureComponent<Props, State> {
 
     const config = newSessionProto.config as Config
     const themeInput = newSessionProto.customTheme as CustomThemeConfig
-    const { currentPageScriptHash } = this.state
+    const { currentPageScriptHash: prevPageScriptHash } = this.state
     const newPageScriptHash = newSessionProto.pageScriptHash
 
     // mainPage must be a string as we're guaranteed at this point that
@@ -741,18 +741,20 @@ export class App extends PureComponent<Props, State> {
     )?.pageName as string
     const viewingMainPage = newPageScriptHash === mainPage.pageScriptHash
 
-    const baseUriParts = this.getBaseUriParts()
-    if (baseUriParts) {
-      const { basePath } = baseUriParts
-      const queryString = this.getQueryString()
+    if (prevPageScriptHash !== newPageScriptHash) {
+      const baseUriParts = this.getBaseUriParts()
+      if (baseUriParts) {
+        const { basePath } = baseUriParts
+        const queryString = this.getQueryString()
 
-      const qs = queryString ? `?${queryString}` : ""
-      const basePathPrefix = basePath ? `/${basePath}` : ""
+        const qs = queryString ? `?${queryString}` : ""
+        const basePathPrefix = basePath ? `/${basePath}` : ""
 
-      const pagePath = viewingMainPage ? "" : newPageName
-      const pageUrl = `${basePathPrefix}/${pagePath}${qs}`
+        const pagePath = viewingMainPage ? "" : newPageName
+        const pageUrl = `${basePathPrefix}/${pagePath}${qs}`
 
-      window.history.pushState({}, "", pageUrl)
+        window.history.pushState({}, "", pageUrl)
+      }
     }
 
     this.processThemeInput(themeInput)
@@ -806,7 +808,7 @@ export class App extends PureComponent<Props, State> {
 
     if (
       appHash === newSessionHash &&
-      currentPageScriptHash === newPageScriptHash
+      prevPageScriptHash === newPageScriptHash
     ) {
       this.setState({
         scriptRunId,


## 📚 Context

_Please describe the project or issue background here_

- What kind of change does this PR introduce?

  - [x] Bugfix
  - [ ] Feature
  - [ ] Refactoring
  - [ ] Other, please describe:

## 🧠 Description of Changes

- _Add bullet points summarizing your changes here_

  - [ ] This is a breaking API change
  - [ ] This is a visible (user-facing) change

## 🧪 Testing Done

- [ ] Screenshots included
- [x] Added/Updated unit tests
- [ ] Added/Updated e2e tests

## 🌐 References

_Does this depend on other work, documents, or tickets?_

- **Issue**: Closes #5292

---

**Contribution License Agreement**

By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.
