Intercept/handle browser's back button in React-router?

前端 未结 12 1011
滥情空心
滥情空心 2020-11-27 03:47

I\'m using Material-ui\'s Tabs, which are controlled and I\'m using them for (React-router) Links like this:

    

        
相关标签:
12条回答
  • It depends on the type of Router you use in React.

    If you use BrowserRouter from react-router (not available in react-router v4 though), as mentioned above, you can use the action 'POP' to intercept the browser back button.

    However, if you use HashRouter to push the routes, above solution will not work. The reason is hash router always triggered with 'POP' action when you click browser back button or pushing the route from your components. You cant differentiate these two actions either with window.popstate or history.listen simply.

    0 讨论(0)
  • 2020-11-27 04:32

    here is how I ended up doing it:

    componentDidMount() {
        this._isMounted = true;
        window.onpopstate = ()=> {
          if(this._isMounted) {
            const { hash } = location;
            if(hash.indexOf('home')>-1 && this.state.value!==0)
              this.setState({value: 0})
            if(hash.indexOf('users')>-1 && this.state.value!==1)
              this.setState({value: 1})
            if(hash.indexOf('data')>-1 && this.state.value!==2)
              this.setState({value: 2})
          }
        }
      }
    

    thanks everybody for helping lol

    0 讨论(0)
  • 2020-11-27 04:32

    Most of the answers for this question either use outdated versions of React Router, rely on less-modern Class Components, or are confusing; and none use Typescript, which is a common combination. Here is an answer using Router v5, function components, and Typescript:

    // use destructuring to access the history property of the ReactComponentProps type
    function MyComponent( { history }: ReactComponentProps) {
    
        // use useEffect to access lifecycle methods, as componentDidMount etc. are not available on function components.
        useEffect(() => {
    
            return () => {
                if (history.action === "POP") {
                    // Code here will run when back button fires. Note that it's after the `return` for useEffect's callback; code before the return will fire after the page mounts, code after when it is about to unmount.
                    }
               }
        })
    }
    

    A fuller example with explanations can be found here.

    0 讨论(0)
  • 2020-11-27 04:36

    Upcoming version 6.0 introduces useBlocker hook - which could be used to intercept all navigation attempts.

    import { Action } from 'history';
    import { useBlocker } from 'react-router';
    
    // when blocker should be active
    const unsavedChanges = true;
    
    useBlocker((transition) => {
        const {
            location, // The new location
            action, // The action that triggered the change
        } = transition;
    
        // intercept back and forward actions:
        if (action === Action.Pop) {
            alert('intercepted!')
        }
    
    }, unsavedChanges);
    
    0 讨论(0)
  • 2020-11-27 04:37

    Hooks sample

    const {history} = useRouter();
      useEffect(() => {
        return () => {
          // && history.location.pathname === "any specific path")
          if (history.action === "POP") {
            history.replace(history.location.pathname, /* the new state */);
          }
        };
      }, [history])
    

    I don't use history.listen because it doesn't affect the state

    const disposeListener = history.listen(navData => {
            if (navData.pathname === "/props") {
                navData.state = /* the new state */;
            }
        });
    
    0 讨论(0)
  • 2020-11-27 04:37

    Using hooks. I have converted @Nicolas Keller's code to typescript

      const [locationKeys, setLocationKeys] = useState<(string | undefined)[]>([]);
      const history = useHistory();
    
      useEffect(() => {
        return history.listen((location) => {
          if (history.action === 'PUSH') {
            if (location.key) setLocationKeys([location.key]);
          }
    
          if (history.action === 'POP') {
            if (locationKeys[1] === location.key) {
              setLocationKeys(([_, ...keys]) => keys);
    
              // Handle forward event
              console.log('forward button');
            } else {
              setLocationKeys((keys) => [location.key, ...keys]);
    
              // Handle back event
              console.log('back button');
              removeTask();
            }
          }
        });
      }, [locationKeys]);
    
    0 讨论(0)
提交回复
热议问题