3

I'm using react-router v5 and I want to upgrade to v6. There is a problem: I have many components and use useHistory inside them but I don't want to change them one by one to useNavigate instead of that I want to write a helper function for navigate(history) in react-router v6 and then use that helper(wrapper) function.

Question is: How to write a helper function for useNavigate in react-router v6?

4
  • 1
    What's wrong with completely replacing all useHistory hooks with the useNavigate hook? If upgrading from RRDv5 to v6 you'll need to do this anyway. What have you tried already? Do you have a minimal reproducible example? Commented Oct 17, 2022 at 7:52
  • one reason is if one day we need to upgrade again just change that helper file and there is no need to change all of the project's files. Commented Oct 17, 2022 at 7:57
  • So you want to create a custom hook that uses useHistory, then upgrade from v5 to v6, and keep using the custom hook? There isn't a 1-1 mapping of the RRDv5 history object to the RRDv6 navigate function. How much of the RRDv5 history object behavior do you want/need to retain? Commented Oct 17, 2022 at 7:59
  • yes, almost and for v6 I can use useNavigate instead of useHistory in it, and maybe for the next version I use another thing if I need. Commented Oct 17, 2022 at 8:04

1 Answer 1

1

If you are wanting to provide a custom navigation utility then you'll likely want to create a custom React hook that "wraps" one of the hooks provided from react-router and return the functions you need. Unfortunately react-router@6 doesn't directly expose out the history object, and there isn't a 1-to-1 relationship between the history object and the navigate function. You can cover most common use cases though. I suggest adhering to a "common API" that fits your needs.

RRDv5 Example

import { useHistory } from 'react-router';

const useMyNavigation = () => {
  const history = useHistory();

  const push = React.useCallback((to, state) => history.push(to, state), []);

  const replace = React.useCallback((to, state) => history.replace(to, state), []);

  const go = React.useCallback((delta) => history.go(delta), []);

  const back = React.useCallback(() => history.back(-1), []);

  const forward = React.useCallback(() => history.go(1), []);

  return {
    back
    forward,
    go,
    push,
    replace
  };
};

RRDv6 Example

import { useNavigate } from 'react-router';

const useMyNavigation = () => {
  const navigate = useNavigate();

  const push = React.useCallback((to, state) => navigate(to, { state }), []);

  const replace = React.useCallback((to, state) => navigate(to, { replace: true, state }), []);

  const go = React.useCallback((delta) => navigate(delta), []);

  const back = React.useCallback(() => navigate(-1), []);

  const forward = React.useCallback(() => navigate(1), []);

  return {
    back
    forward,
    go,
    push,
    replace
  };
};

Alternative RRDv6 Example

Now, when I said that RRDv6 doesn't directly expose out the history object, this isn't entirely true. It does not directly export the history object, but it does export the React context holding it via the UNSAFE_NavigationContext context. With this you can get a reference to the navigator function which is a history@5 history object (as opposed to the history@4 that RRDv5 uses). Note that this likely requires history@5 (the same version used by react-router@6) to be listed as a project dependency. See history@5 Navigation.

import { useContext } from 'react';
import { useNavigate } from 'react-router';

const useMyNavigation = () => {
  const navigator = useContext(UNSAFE_NavigationContext).navigator;

  const push = React.useCallback((to, state) => navigator.push(to, state), []);

  const replace = React.useCallback((to, state) => navigator.replace(to, state), []);

  const go = React.useCallback((delta) => navigator.go(delta), []);

  const back = React.useCallback(() => navigator.back(-1), []);

  const forward = React.useCallback(() => navigator.go(1), []);

  return {
    back
    forward,
    go,
    push,
    replace
  };
};
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.