web-dev-qa-db-fra.com

Appuyez sur le bouton Retour dans React ne recharge pas la page

J'ai une application React (16.8.6) écrite en TypeScript qui utilise React Router (5.0.1) et MobX (5.9.4). La navigation fonctionne correctement et les données se chargent quand cela devrait, cependant, lorsque je clique sur le bouton Précédent du navigateur, l'URL change mais aucun état n'est mis à jour et la page n'est pas restituée. J'ai lu des articles sans fin sur ce problème et sur le withRouter fixer, que j'ai essayé mais cela ne fait aucune différence.

Un cas d'utilisation typique consiste à naviguer vers la page de résumé, à sélectionner diverses choses qui provoquent le chargement de nouvelles données et de nouveaux états d'historique, puis à revenir en arrière sur quelques étapes jusqu'à l'endroit où vous avez commencé. La plupart des poussées d'historique se produisent dans le composant récapitulatif, qui gère plusieurs itinéraires. J'ai remarqué qu'en revenant de la page de résumé à la page d'accueil, le nouveau rendu se déroule comme il se doit.

Mon index.tsx

import { Provider } from 'mobx-react'
import * as React from 'react'
import * as ReactDOM from 'react-dom'

import App from './App'
import * as serviceWorker from './serviceWorker'
import * as Utils from './utils/Utils'

const rootStore = Utils.createStores()

ReactDOM.render(
    <Provider {...rootStore }>
        <App />
    </Provider>,
    document.getElementById('root') as HTMLElement
)

serviceWorker.unregister()

Mon app.tsx

import * as React from 'react'
import { inject, observer } from 'mobx-react'
import { Route, Router, Switch } from 'react-router'

import Home from './pages/Home/Home'
import PackageSummary from './pages/PackageSummary/PackageSummary'
import ErrorPage from './pages/ErrorPage/ErrorPage'
import { STORE_ROUTER } from './constants/Constants'
import { RouterStore } from './stores/RouterStore'

@inject(STORE_ROUTER)
@observer
class App extends React.Component {
    private routerStore = this.props[STORE_ROUTER] as RouterStore

    public render() {
        return (
            <Router history={this.routerStore.history}>
                <Switch>
                    <Route exact path="/" component={Home} />
                    <Route exact path="/summary/:packageId" component={PackageSummary} />
                    <Route exact path="/summary/:packageId/:menuName" component={PackageSummary} />
                    <Route exact path="/summary/:packageId/:menuName/:appName" component={PackageSummary} />
                    <Route component={ErrorPage} />
                </Switch>
            </Router>
        )
    }
}

export default App

Ma boutique de routeurs

import { RouterStore as BaseRouterStore, syncHistoryWithStore } from 'mobx-react-router'
import { createBrowserHistory } from 'history'

export class RouterStore extends BaseRouterStore {
    constructor() {
        super()
        this.history = syncHistoryWithStore(createBrowserHistory(), this)
    }
}

Comment je crée les magasins MobX

export const createStores = () => {
    const routerStore = new RouterStore()
    const packageListStore = new PackageListStore()
    const packageSummaryStore = new PackageSummaryStore()
    const packageUploadStore = new PackageUploadStore()

    return {
        [STORE_ROUTER]: routerStore,
        [STORE_SUPPORT_PACKAGE_LIST]: packageListStore,
        [STORE_SUPPORT_PACKAGE_SUMMARY]: packageSummaryStore,
        [STORE_SUPPORT_PACKAGE_UPLOAD]: packageUploadStore
    }
}

Mes questions sont donc:

  1. Comment puis-je obtenir la page pour charger les données appropriées lorsque l'utilisateur retourne/avance via le navigateur?
  2. Si la solution permet à MobX d'observer les modifications de l'emplacement, comment dois-je procéder?
10
Chris Tybur

Vous pouvez implémenter quelque chose comme ceci dans votre composant:

import { inject, observer } from 'mobx-react';
import { observe } from 'mobx';

@inject('routerStore')
@observer
class PackageSummary extends React.Component {
  listener = null;
  componentDidMount() {
    this.listener = observe(this.props.routerStore, 'location', ({ oldValue, newValue }) => {
      if (!oldValue || oldValue.pathname !== newValue.pathname) {
        // your logic
      }
    }, true)
  }

  componentWillUnmount() {
    this.listener();
  }
}

Le problème avec cette approche est que si vous revenez de /summary vers une autre page (par exemple '/'), le rappel sera lancé, vous aurez donc également besoin d'une sorte de vérification de l'itinéraire. En raison de ce type de complications, je suggère d'utiliser mobx-state-router , que j'ai trouvé beaucoup mieux à utiliser avec MobX.

2
zhuber

Le routeur React surveille les changements d'URL et rend le composant associé défini pour l'itinéraire alias url. Vous devez actualiser manuellement ou appeler une fonction de fenêtre pour recharger.

1
att

Je ne sais pas si vous l'avez déjà vu, mais cette réponse pourrait peut-être vous aider ou au moins vous donner une idée de la façon dont réagir pour résoudre ces problèmes.

https://stackoverflow.com/a/39363278/9208722

1

Si je me souviens bien, l'utilisation d'une fonction de retour de navigateur ne recharge pas la page (je peux me tromper).

Pourquoi ne pas essayer de détecter l'action de retour par un navigateur et recharger la page lorsqu'elle est détectée à la place?

Vous pouvez essayer le code suivant pour recharger manuellement la page lorsque vous cliquez sur le bouton de retour du navigateur.

$(window).bind("pageshow", function() {
  // Run reload code here.
});

Aussi par curiosité, pourquoi avez-vous besoin de tant de magasins différents?

1
Norman