প্রতিক্রিয়া-রাউটার দিয়ে ব্যবহারকারী প্রস্থান পৃষ্ঠা সনাক্ত করা হচ্ছে


115

আমি চাইব আমার রেএ্যাকটিজেএস অ্যাপটি কোনও নির্দিষ্ট পৃষ্ঠা থেকে দূরে নেভিগেট করার সময় কোনও ব্যবহারকারীকে অবহিত করা উচিত। বিশেষত একটি পপআপ বার্তা যা তাকে / তাকে কোনও ক্রিয়া করানোর জন্য মনে করিয়ে দেয়:

"পরিবর্তনগুলি সংরক্ষিত হয়েছে, তবে এখনও প্রকাশিত হয়নি that এখন কি তাই করবেন?"

আমি কি react-routerবিশ্বব্যাপী এটি ট্রিগার করা উচিত , বা এটি এমন কিছু যা প্রতিক্রিয়া পৃষ্ঠা / উপাদানটির মধ্যে থেকে করা যায়?

আমি পরের দিকে কিছু খুঁজে পাইনি, এবং আমি বরং প্রথমটি এড়াতে চাই। অবশ্যই এটির আদর্শ না থাকলে তবে ব্যবহারকারীরা যে সমস্ত সম্ভাব্য পৃষ্ঠায় কোড যুক্ত না করেই কীভাবে এমন কাজ করবেন তা আমাকে অবাক করে দেয় ..

কোন অন্তর্দৃষ্টি স্বাগত, ধন্যবাদ!


3
আপনি এখন যা খুঁজছেন তা যদি এখন হয় তবে আমি তা করতে পারি না st এটি পছন্দ করুন componentWillUnmount() { if (confirm('Changes are saved, but not published yet. Do that now?')) { // publish and go away from a specific page } else { // do nothing and go away from a specific page } }যাতে আপনি পৃষ্ঠাটি ছেড়ে আপনার প্রকাশিত ফাংশনটিকে কল করতে পারেন
রিকো বার্গার

উত্তর:


153

react-routerভি 4 ব্যবহার করে নেভিগেশন অবরোধ করার জন্য একটি নতুন উপায় প্রবর্তন করে Prompt। আপনি যে উপাদানটি অবরুদ্ধ করতে চান তা কেবল এটিতে যুক্ত করুন:

import { Prompt } from 'react-router'

const MyComponent = () => (
  <React.Fragment>
    <Prompt
      when={shouldBlockNavigation}
      message='You have unsaved changes, are you sure you want to leave?'
    />
    {/* Component JSX */}
  </React.Fragment>
)

এটি কোনও রাউটিংকে ব্লক করবে, তবে পৃষ্ঠা রিফ্রেশ বা বন্ধ হবে না। এটিকে অবরুদ্ধ করতে আপনাকে এটি যুক্ত করতে হবে (যথাযথ প্রতিক্রিয়া লাইফসাইকের সাথে প্রয়োজনীয় হিসাবে আপডেট করা):

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

ব্রাউজারগুলির দ্বারা onbeforeunload এর বিভিন্ন সমর্থন রয়েছে।


9
যদিও এটির ফলাফল দুটি খুব আলাদা দেখায় সতর্কতা দেয়।
এক্সানডারস্ট্রাইক 16

3
@ এক্সান্দার স্ট্রাইক আপনি ব্রাউজারের ডিফল্ট সতর্কতার অনুকরণে প্রম্পট সতর্কতাটিকে স্টাইল করার চেষ্টা করতে পারেন। দুর্ভাগ্যক্রমে, onberforeunloadসতর্কতার স্টাইল করার কোনও উপায় নেই ।
jcady

উদাহরণস্বরূপ যখন ব্যবহারকারী কোনও ক্যানসেল বাটনে ক্লিক করেন তখন একই প্রম্পট উপাদানটি দেখানোর কোনও উপায় আছে কি?
রেনে এনরিকিক্স

1
@ রেনেইনরিক্স react-routerবাক্সের বাইরে এটি সমর্থন করে না (ধরে নিলাম বাতিল বোতামটি কোনও রুটের পরিবর্তনকে ট্রিগার করে না)। যদিও আচরণটি নকল করতে আপনি নিজের মডেল তৈরি করতে পারেন।
jcady

6
যদি আপনি onbeforeunload ব্যবহারটি শেষ করেন , আপনার উপাদানটি আনমাট করার সময় আপনি এটিকে পরিষ্কার করতে চাইবেন। componentWillUnmount() { window.onbeforeunload = null; }
cdeutsch

40

রিঅ্যাক্ট-রাউটারে v2.4.0বা তার উপরে এবং তার আগে v4বেশ কয়েকটি বিকল্প রয়েছে

  1. এর onLeaveজন্য ফাংশন যুক্ত করুনRoute
 <Route
      path="/home"
      onEnter={ auth }
      onLeave={ showConfirm }
      component={ Home }
    >
  1. setRouteLeaveHookজন্য ফাংশন ব্যবহার করুনcomponentDidMount

ছুটি হুক দিয়ে কোনও রুট ছাড়ার আগে আপনি কোনও সংক্রমণ ঘটতে বা আটকাতে বা রোধ করতে পারেন।

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?'
    },

    // ...

  })
)

মনে রাখবেন যে এই উদাহরণটি withRouterউচ্চতর অর্ডার উপাদানটি চালু করেv2.4.0.

তবে ইউআরএলটিতে ম্যানুয়ালি রুট পরিবর্তন করার সময় এই সমাধানগুলি পুরোপুরি কার্যকর হয় না

এই ভেবে যে

  • আমরা নিশ্চিতকরণটি দেখতে পাই - ঠিক আছে
  • পৃষ্ঠা ধারণ করে পুনরায় লোড হয় না - ঠিক আছে
  • ইউআরএল পরিবর্তন হয় না - ঠিক আছে না

react-router v4প্রম্পট বা কাস্টম ইতিহাস ব্যবহারের জন্য :

তবে এতে react-router v4, Promptআরে্যাক্ট-রাউটারের সাহায্যে প্রয়োগ করা বরং আরও সহজ

ডকুমেন্টেশন অনুযায়ী

শীঘ্র

কোনও পৃষ্ঠা থেকে দূরে নেভিগেটের আগে ব্যবহারকারীকে অনুরোধ জানাতে ব্যবহৃত হয়। যখন আপনার অ্যাপ্লিকেশন এমন একটি স্থানে প্রবেশ করে যা ব্যবহারকারীকে চলাচল করা থেকে বিরত রাখতে পারে (যেমন একটি ফর্মটি অর্ধ-ভরাট হয়), তখন রেন্ডার করুন a <Prompt>

import { Prompt } from 'react-router'

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

বার্তা: স্ট্রিং

ব্যবহারকারীরা যখন নেভিগেট করার চেষ্টা করবে তখন সেই বার্তাটি প্রম্পট করার জন্য।

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

বার্তা: ফানক

পরবর্তী অবস্থান এবং ব্যবহারকারীটি নেভিগেট করার চেষ্টা করছে এমন ক্রিয়া সহ ডাকা হবে। ব্যবহারকারীর কাছে প্রম্পট দেখাতে একটি স্ট্রিং ফিরিয়ে দিন বা ট্রানজিশনের অনুমতি দেওয়ার জন্য সত্য।

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

কখন: বুল

শর্তসাপেক্ষে <Prompt>কোনও প্রহরীকে পিছনে রেন্ডার করার পরিবর্তে , আপনি সর্বদা এটি রেন্ডার করতে পারেন তবে পাস করতে পারেন when={true}বা when={false}সেই অনুযায়ী নেভিগেশনকে আটকাতে বা অনুমতি দিতে পারেন।

আপনার রেন্ডার পদ্ধতিতে আপনার প্রয়োজন অনুসারে ডকুমেন্টেশনে উল্লিখিতভাবে আপনাকে এটি যুক্ত করতে হবে।

হালনাগাদ:

আপনি যখন পৃষ্ঠাটি ছেড়ে যাচ্ছেন তখন আপনি কোনও কাস্টম পদক্ষেপ নিতে চান, আপনি কাস্টম ইতিহাস ব্যবহার করতে পারেন এবং আপনার রাউটারের মতো কনফিগার করতে পারেন

history.js

import createBrowserHistory from 'history/createBrowserHistory'
export const history = createBrowserHistory()

... 
import { history } from 'path/to/history';
<Router history={history}>
  <App/>
</Router>

এবং তারপরে আপনার উপাদানটিতে আপনি history.blockপছন্দ মতো ব্যবহার করতে পারেন

import { history } from 'path/to/history';
class MyComponent extends React.Component {
   componentDidMount() {
      this.unblock = history.block(targetLocation => {
           // take your action here     
           return false;
      });
   }
   componentWillUnmount() {
      this.unblock();
   }
   render() {
      //component render here
   }
}

1
এমনকি আপনি যদি <Prompt>প্রম্পটে বাতিল চাপুন তখন ইউআরএল ব্যবহার করা হলেও পরিবর্তন হয়ে যায়। সম্পর্কিত সমস্যা: github.com/ReactTraining/react-router/issues/5405
সাহান

1
আমি এই প্রশ্নটি এখনও বেশ জনপ্রিয়। যেহেতু শীর্ষস্থানীয় উত্তরগুলি পুরানো অবনমিত সংস্করণগুলির জন্য, তাই আমি এই নতুন উত্তরটিকে গৃহীত উত্তর হিসাবে সেট করেছি। পুরানো ডকুমেন্টেশনের লিঙ্কগুলি (এবং আপগ্রেড গাইডগুলি) এখন github.com/ReactTraining/react-router
ব্যারি

1
অন ​​রুট পরিবর্তনের বিষয়টি নিশ্চিত হওয়ার পরে চালককে গুলি চালানো হয়। কীভাবে অন লাইভে একটি নেভিগেশন বাতিল করবেন সে সম্পর্কে বিস্তারিত বলতে পারেন?
schlingel

23

জন্য react-router2.4.0+

দ্রষ্টব্য : react-routerনতুন সমস্ত জিনিসপত্র পেতে আপনার সমস্ত কোড সর্বশেষে স্থানান্তরিত করার পরামর্শ দেওয়া হচ্ছে ।

প্রতিক্রিয়া-রাউটার ডকুমেন্টেশনে প্রস্তাবিত হিসাবে :

withRouterউচ্চতর অর্ডার উপাদান ব্যবহার করা উচিত :

আমরা মনে করি যে এই নতুন হউকটি আরও সুন্দর এবং সহজ, এবং এটি ডকুমেন্টেশন এবং উদাহরণগুলিতে ব্যবহার করবে, তবে এটি স্যুইচ করা কোনও কঠিন প্রয়োজন নয়।

ডকুমেন্টেশন থেকে ES6 উদাহরণ হিসাবে:

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)

4
রুটলিভহুক কলব্যাক কী করে? এটি কি অন্তর্নির্মিত মডেল ব্যবহার করে ব্যবহারকারীকে অনুরোধ করে? আপনি যদি একটি কাস্টম মডেল চান তবে কী
লার্নার

@Learner- এর মতো: ভেক্স বা সুইটএলার্ট বা অন্যান্য অ-ব্লক করা কথোপকথনের মতো একটি কাস্টমাইজড কনফার্মেশন বাক্সের সাহায্যে এটি কীভাবে করা যায়?
olefrank

আমি নিম্নলিখিত ত্রুটি করছি: - টাইপরর: অপরিজ্ঞাতকৃত সম্পত্তি ' আইডি ' পড়তে পারে না । যে কোনও পরামর্শ
মোস্তফা মামুন

@ মুস্তফামামুন এটি কোনও সম্পর্কযুক্ত সমস্যা বলে মনে হচ্ছে এবং আপনি বেশিরভাগই বিশদ ব্যাখ্যা করে একটি নতুন প্রশ্ন তৈরি করতে চাইবেন।
snymkpr

সমাধানটি ব্যবহার করার চেষ্টা করার সময় আমার সমস্যা ছিল। উপাদানটি সরাসরি রাউটারের সাথে সংযুক্ত করতে হবে তারপরে এই সমাধানটি কাজ করে। আমি সেখানে একটি আরও ভাল উত্তর পেয়েছি stackoverflow.com/questions/39103684/…
মোস্তফা মামুন

4

জন্য react-routerv3.x

আমার একই সমস্যা ছিল যেখানে আমার পৃষ্ঠায় কোনও সংরক্ষিত পরিবর্তনের জন্য একটি নিশ্চিতকরণ বার্তা প্রয়োজন। আমার ক্ষেত্রে, আমি প্রতিক্রিয়া রাউটার v3 ব্যবহার করছিলাম , তাই আমি ব্যবহার করতে পারিনি <Prompt />, যা প্রতিক্রিয়া রাউটার ভি 4 থেকে চালু হয়েছিল ।

আমি সমন্বয় সঙ্গে 'ব্যাক বোতাম ক্লিকের' এবং 'আপতিক লিঙ্কটি ক্লিক' ঘাঁটা setRouteLeaveHookএবং history.pushState(), এবং 'পুনরায় লোড করুন বোতামটি' ঘাঁটা onbeforeunloadইভেন্ট হ্যান্ডলার।

setRouteLeaveHook ( ডক ) & history.pushState ( ডক )

  • কেবল সেটআরউটলিউহুক ব্যবহার করা যথেষ্ট ছিল না। কোনও কারণে, URL টি পরিবর্তন করা হয়েছিল যদিও 'পিছনে বোতাম' ক্লিক করার সময় পৃষ্ঠাটি একই ছিল।

      // setRouteLeaveHook returns the unregister method
      this.unregisterRouteHook = this.props.router.setRouteLeaveHook(
        this.props.route,
        this.routerWillLeave
      );
    
      ...
    
      routerWillLeave = nextLocation => {
        // Using native 'confirm' method to show confirmation message
        const result = confirm('Unsaved work will be lost');
        if (result) {
          // navigation confirmed
          return true;
        } else {
          // navigation canceled, pushing the previous path
          window.history.pushState(null, null, this.props.route.path);
          return false;
        }
      };

অনবিতুনলোড ( ডক )

  • এটি 'দুর্ঘটনাজনিত পুনরায় লোড' বোতামটি হ্যান্ডেল করতে ব্যবহৃত হয়

    window.onbeforeunload = this.handleOnBeforeUnload;
    
    ...
    
    handleOnBeforeUnload = e => {
      const message = 'Are you sure?';
      e.returnValue = message;
      return message;
    }

নীচে আমি লিখেছি যে সম্পূর্ণ উপাদান

  • নোট করুন যে উইথ রউটারটি ব্যবহার করতে ব্যবহৃত হয় this.props.router
  • this.props.routeকলিং উপাদান থেকে নিচে দেওয়া হয়েছে নোট
  • নোটটি currentStateপ্রারম্ভিক অবস্থা এবং কোনও পরিবর্তন পরীক্ষা করতে প্রপোজ হিসাবে পাস করা হয়েছে

    import React from 'react';
    import PropTypes from 'prop-types';
    import _ from 'lodash';
    import { withRouter } from 'react-router';
    import Component from '../Component';
    import styles from './PreventRouteChange.css';
    
    class PreventRouteChange extends Component {
      constructor(props) {
        super(props);
        this.state = {
          // initialize the initial state to check any change
          initialState: _.cloneDeep(props.currentState),
          hookMounted: false
        };
      }
    
      componentDidUpdate() {
    
       // I used the library called 'lodash'
       // but you can use your own way to check any unsaved changed
        const unsaved = !_.isEqual(
          this.state.initialState,
          this.props.currentState
        );
    
        if (!unsaved && this.state.hookMounted) {
          // unregister hooks
          this.setState({ hookMounted: false });
          this.unregisterRouteHook();
          window.onbeforeunload = null;
        } else if (unsaved && !this.state.hookMounted) {
          // register hooks
          this.setState({ hookMounted: true });
          this.unregisterRouteHook = this.props.router.setRouteLeaveHook(
            this.props.route,
            this.routerWillLeave
          );
          window.onbeforeunload = this.handleOnBeforeUnload;
        }
      }
    
      componentWillUnmount() {
        // unregister onbeforeunload event handler
        window.onbeforeunload = null;
      }
    
      handleOnBeforeUnload = e => {
        const message = 'Are you sure?';
        e.returnValue = message;
        return message;
      };
    
      routerWillLeave = nextLocation => {
        const result = confirm('Unsaved work will be lost');
        if (result) {
          return true;
        } else {
          window.history.pushState(null, null, this.props.route.path);
          if (this.formStartEle) {
            this.moveTo.move(this.formStartEle);
          }
          return false;
        }
      };
    
      render() {
        return (
          <div>
            {this.props.children}
          </div>
        );
      }
    }
    
    PreventRouteChange.propTypes = propTypes;
    
    export default withRouter(PreventRouteChange);

কোন প্রশ্ন থাকলে দয়া করে আমাকে জানান :)


এই.ফর্মস্টার্টল কোথা থেকে আসছে?
গৌরব

2

জন্য react-routerসঙ্গে v0.13.x reactv0.13.x:

এই সঙ্গে সম্ভব willTransitionTo()এবং willTransitionFrom()স্ট্যাটিক পদ্ধতি। আরও নতুন সংস্করণগুলির জন্য, নীচে আমার অন্যান্য উত্তর দেখুন।

থেকে প্রতিক্রিয়া-রাউটার ডকুমেন্টেশন :

আপনি আপনার রুট হ্যান্ডলারগুলিতে কিছু স্থিতিশীল পদ্ধতি সংজ্ঞায়িত করতে পারেন যা রুট ট্রানজিশনের সময় ডাকা হবে।

willTransitionTo(transition, params, query, callback)

যখন কোনও হ্যান্ডলার রেন্ডার করতে চলেছে তখন আপনাকে এই রূপান্তরটি বাতিল বা পুনঃনির্দেশ করার সুযোগ দেয়। আপনি যখন কিছু অ্যাসিঙ্কনাস কাজ করেন তখন কল্পনাটি থামিয়ে দিতে পারেন এবং আপনার কাজ শেষ হয়ে গেলে কল কলব্যাক (ত্রুটি) করতে পারেন বা আপনার যুক্তি তালিকায় কলব্যাক বাদ দিতে পারেন এবং এটি আপনার জন্য ডাকা হবে।

willTransitionFrom(transition, component, callback)

যখন সক্রিয় রুটটি আপনাকে রূপান্তর বাতিল করার সুযোগ দেয় তখনই স্থানান্তরিত হয়। উপাদানটি হ'ল বর্তমান উপাদান, আপনি সম্ভবত রূপান্তরের অনুমতি দিতে চান (যেমন ফর্ম ক্ষেত্রগুলি) চান কিনা তা স্থির করার জন্য এটির অবস্থা পরীক্ষা করার প্রয়োজন সম্ভবত।

উদাহরণ

  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();
          }
        }
      }
    }

    //...
  });

V0.14.x বা তার পরে react-router1.0.0-আরসি 1 এর জন্য react:

এটি routerWillLeaveলাইফেসাইকেল হুক দিয়ে সম্ভব হওয়া উচিত । পুরানো সংস্করণগুলির জন্য, আমার উত্তর উপরে দেখুন।

থেকে প্রতিক্রিয়া-রাউটার ডকুমেন্টেশন :

এই হুকটি ইনস্টল করতে আপনার রুট উপাদানগুলির একটিতে লাইফাইসাইকেল মিশিন ব্যবহার করুন।

  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?'
    },

    // ...

  })

থিংস। যদিও চূড়ান্ত প্রকাশের আগে পরিবর্তন হতে পারে।


1

আপনি এই প্রম্পটটি ব্যবহার করতে পারেন।

import React, { Component } from "react";
import { BrowserRouter as Router, Route, Link, Prompt } from "react-router-dom";

function PreventingTransitionsExample() {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/">Form</Link>
          </li>
          <li>
            <Link to="/one">One</Link>
          </li>
          <li>
            <Link to="/two">Two</Link>
          </li>
        </ul>
        <Route path="/" exact component={Form} />
        <Route path="/one" render={() => <h3>One</h3>} />
        <Route path="/two" render={() => <h3>Two</h3>} />
      </div>
    </Router>
  );
}

class Form extends Component {
  state = { isBlocking: false };

  render() {
    let { isBlocking } = this.state;

    return (
      <form
        onSubmit={event => {
          event.preventDefault();
          event.target.reset();
          this.setState({
            isBlocking: false
          });
        }}
      >
        <Prompt
          when={isBlocking}
          message={location =>
            `Are you sure you want to go to ${location.pathname}`
          }
        />

        <p>
          Blocking?{" "}
          {isBlocking ? "Yes, click a link or the back button" : "Nope"}
        </p>

        <p>
          <input
            size="50"
            placeholder="type something to block transitions"
            onChange={event => {
              this.setState({
                isBlocking: event.target.value.length > 0
              });
            }}
          />
        </p>

        <p>
          <button>Submit to stop blocking</button>
        </p>
      </form>
    );
  }
}

export default PreventingTransitionsExample;

1

হিস্টরি.লাইস্টেন ব্যবহার করে

উদাহরণস্বরূপ নীচের মত:

আপনার উপাদান,

componentWillMount() {
    this.props.history.listen(() => {
      // Detecting, user has changed URL
      console.info(this.props.history.location.pathname);
    });
}

5
হাই, স্ট্যাক ওভারফ্লোতে আপনাকে স্বাগতম ইতিমধ্যে অনেক প্রশ্নের উত্তর রয়েছে এমন প্রশ্নের উত্তর দেওয়ার সময়, দয়া করে আপনার যে প্রতিক্রিয়া সরবরাহ করছেন তা কেন দৃtive় এবং মূল পোস্টার দ্বারা ইতিমধ্যে যা অনুসন্ধান করা হয়েছে তা প্রতিধ্বনিত করে না কেন সে সম্পর্কে কিছু অতিরিক্ত অন্তর্দৃষ্টি যোগ করার বিষয়ে নিশ্চিত হন। এটি "কোড-কেবল" উত্তরের ক্ষেত্রে বিশেষত গুরুত্বপূর্ণ যা আপনি সরবরাহ করেছেন important
chb
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.