2015-09-29 2 views
17

Ich möchte, dass meine ReactJS-App einen Benutzer benachrichtigt, wenn er von einer bestimmten Seite weg navigiert. Insbesondere eine Popup-Nachricht, die ihn erinnert/ihr eine Aktion tun:Ermitteln des Benutzers beim Verlassen der Seite

"Changes are saved, but not published yet. Do that now?"

Soll ich auslösen diese auf react-router global, oder ist dies etwas, das innerhalb der Seite/Komponente reagieren kann getan werden?

Ich habe nichts auf letzterem gefunden, und ich würde eher die erste vermeiden. Es sei denn, seine Norm natürlich, aber das macht mich fragen, wie so etwas zu tun, ohne den Code zu jeder anderen möglichen Seite hinzufügen zu müssen die Benutzer gehen ..

Keine Erkenntnisse gern gesehen, danke!

+3

ich nicht jetzt, wenn dies ist, was Sie suchen, aber man kann etw tun. wie diese 'componentWillUnmount() { if (confirm ('Änderungen sind gespeichert, aber noch nicht veröffentlicht. Tun Sie das jetzt?')) { // Veröffentlichen und von einer bestimmten Seite } else { // nichts tun und gehen weg von einer bestimmten Seite } } 'so können Sie Ihren Anruf veröffentlichen Funktion Bevor verlassen der Seite – BlackSalt

Antwort

13

Für react-router 2.4.0+

HINWEIS: Es ist ratsam, auf die neueste react-router den gesamten Code zu migrieren alle neuen Leckereien zu bekommen.

Wie in der react-router documentation empfohlen:

We think this new HoC is nicer and easier, and will be using it in documentation and examples, but it is not a hard requirement to switch.

Als ES6 Beispiel aus der Dokumentation:

import React from 'react' 
import { withRouter } from 'react-router' 

const Page = React.createClass({ 

    componentDidMount() { 
    this.props.router.setRouteLeaveHook(this.props.route,() => { 
     if (this.state.unsaved) 
     return 'You have unsaved information, are you sure you want to leave this page?' 
    }) 
    } 

    render() { 
    return <div>Stuff</div> 
    } 

}) 

export default withRouter(Page) 
+2

Was bedeutet die RouteLeaveHook Rückruf tun? Wird der Benutzer aufgefordert, ein eingebautes Modal zu verwenden? Was passiert, wenn Sie – Learner

+0

Wie @Learner eine benutzerdefinierte modal wollen: Wie dies mit einer angepassten bestätigen Feld wie Vex oder SweetAlert oder andere nicht-blockierenden Dialog? – olefrank

+0

Ich habe folgende Fehlermeldung: - Typeerror: kann Eigenschaft ‚__id__‘ undefinierten lesen. Jeder Vorschlag –

2

Für react-router v0.13.x mit react v0.13.x:

dies möglich ist, mit den willTransitionTo() und willTransitionFrom() statischen Methoden. Für neuere Versionen, siehe meine andere Antwort unten.

Vom react-router documentation:

You can define some static methods on your route handlers that will be called during route transitions.

willTransitionTo(transition, params, query, callback)

Called when a handler is about to render, giving you the opportunity to abort or redirect the transition. You can pause the transition while you do some asynchonous work and call callback(error) when you're done, or omit the callback in your argument list and it will be called for you.

willTransitionFrom(transition, component, callback)

Called when an active route is being transitioned out giving you an opportunity to abort the transition. The component is the current component, you'll probably need it to check its state to decide if you want to allow the transition (like form fields).

Example

var Settings = React.createClass({ 
    statics: { 
     willTransitionTo: function (transition, params, query, callback) { 
     auth.isLoggedIn((isLoggedIn) => { 
      transition.abort(); 
      callback(); 
     }); 
     }, 

     willTransitionFrom: function (transition, component) { 
     if (component.formHasUnsavedData()) { 
      if (!confirm('You have unsaved information,'+ 
         'are you sure you want to leave this page?')) { 
      transition.abort(); 
      } 
     } 
     } 
    } 

    //... 
    }); 

Für react-router 1.0.0-rc1 mit react v0.14.x oder später:

dies mit dem routerWillLeave Lifecycle Haken möglich sein sollte, . Für ältere Versionen, siehe meine Antwort oben.

Vom react-router documentation:

To install this hook, use the Lifecycle mixin in one of your route components.

import { Lifecycle } from 'react-router' 

    const Home = React.createClass({ 

    // Assuming Home is a route component, it may use the 
    // Lifecycle mixin to get a routerWillLeave method. 
    mixins: [ Lifecycle ], 

    routerWillLeave(nextLocation) { 
     if (!this.state.isSaved) 
     return 'Your work is not saved! Are you sure you want to leave?' 
    }, 

    // ... 

    }) 

Dinge. kann sich jedoch vor der endgültigen Veröffentlichung ändern.

7

In reagieren-Router v2.4.0

Eine der withRouter höherer Ordnung Komponente verwenden sollten oder höher und vor v4 gibt es mehrere Optionen

  1. Add function onLeave for Route
<Route 
     path="/home" 
     onEnter={ auth } 
     onLeave={ showConfirm } 
     component={ Home } 
    > 
  1. Use function setRouteLeaveHook for componentDidMount

Sie einen Übergang verhindern kann, geschieht oder den Benutzer auffordern, bevor eine Route verlassen mit einem Haken verlassen.

const Home = withRouter(
    React.createClass({ 

    componentDidMount() { 
     this.props.router.setRouteLeaveHook(this.props.route, this.routerWillLeave) 
    }, 

    routerWillLeave(nextLocation) { 
     // return false to prevent a transition w/o prompting the user, 
     // or return a string to allow the user to decide: 
     // return `null` or nothing to let other hooks to be executed 
     // 
     // NOTE: if you return true, other hooks will not be executed! 
     if (!this.state.isSaved) 
     return 'Your work is not saved! Are you sure you want to leave?' 
    }, 

    // ... 

    }) 
) 

Beachten Sie, dass dieses Beispiel der Verwendung der in v2.4.0. eingeführt withRouter höhere Ordnung Komponente macht

Allerdings hat diese Lösung ganz perfekt funktioniert nicht, wenn die Strecke in URL zu ändern manuell

Im Sinne dass

  • sehen wir die Bestätigung - ok
  • enthalten der Seite nicht neu geladen - ok
  • URL nicht ändert - nicht in Ordnung

jedoch in react-router v4, sein eher einfacher mit Hilfe von Prompt from'react-Router zu implementieren

gemäß der Dokumentation

Prompt

Used to prompt the user before navigating away from a page. When your application enters a state that should prevent the user from navigating away (like a form is half-filled out), render a <Prompt> .

import { Prompt } from 'react-router' 

<Prompt 
    when={formIsHalfFilledOut} 
    message="Are you sure you want to leave?" 
/> 

message: string

The message to prompt the user with when they try to navigate away.

<Prompt message="Are you sure you want to leave?"/> 

message: func

Will be called with the next location and action the user is attempting to navigate to. Return a string to show a prompt to the user or true to allow the transition.

<Prompt message={location => (
    `Are you sure you want to go to ${location.pathname}?` 
)}/> 

when: bool

Instead of conditionally rendering a <Prompt> behind a guard, you can always render it but pass when={true} or when={false} to prevent or allow navigation accordingly.

in Ihrem render-Methode Sie einfach diese hinzufügen müssen, wie in der Dokumentation erwähnt Ihre nee nach d.

1

react-router v4 stellt eine neue Art und Weise Navigation mit Prompt zu blockieren. fügen Sie diese einfach auf die Komponente, die Sie blockieren möchten:

import { Prompt } from 'react-router' 

<Prompt 
    when={shouldBlockNavigation} 
    message='You have unsaved changes, are you sure you want to leave?' 
/> 

Dadurch werden alle Routing-Block, aber nicht Aktualisierung der Seite oder Schließen. Um das zu blockieren, müssen Sie diese hinzufügen (Aktualisierung als mit dem entsprechenden Lebenszyklus benötigt Reagierens):

componentDidUpdate =() => { 
    if (shouldBlockNavigation) { 
    window.onbeforeunload =() => true 
    } else { 
    window.onbeforeunload = undefined 
    } 
} 

onbeforeunload verschiedene Unterstützung von Browsern haben.

Verwandte Themen