Home > Blockchain >  Is possible to override History.push method of React-Router-Dom
Is possible to override History.push method of React-Router-Dom

Time:08-26

I want to attach a computed value of query string into URL whenever user navigates with history.push method.

here is my code

let pusher: null | ((a: unknown, b?: unknown) => void) = null;

/**
 * This hook will push a hashed value of query string of the url
 * 
 * Don't mind about memory leak, it's `Singletom`
 * @param history an instance of History from useHistory
 * @returns `Pusher` an enhance version of `History.push`
 */
export default function useHashPusher(history: ReturnType<typeof useHistory>){

    const sha256 = useSha256();

    if(!pusher) {
        pusher = function(...args) {
            const data = args[0];
            if(typeof data === 'object' && data && 'search' in data){
                const raw = data['search' as keyof typeof data];
                if(raw){
                    const hashed = sha256.hash(raw);
                    (data['search' as keyof typeof data] as string) = `${raw}&hash=${hashed}`;
                    console.log(data);
                }
            }
            console.log('overrided!', args[0]);
            history.push(...args);
        };
    }
    
    return pusher;
}

It works OK but I have to update code at many place from history.push to my pusher

Is there any way to override the history.push method? I'm using react-router-dom v5

CodePudding user response:

It looks like my commented suggestion does work. In a separate file create and export a custom history object.

Example:

import { createBrowserHistory, History } from "history";
import { sha256 } from "../path/to/sha256"; // *

const historyBase = createBrowserHistory();

const history: History = {
  ...historyBase,
  push: (...args) => {
    const data = args[0];
    if (typeof data === "object" && data && "search" in data) {
      const raw = data["search" as keyof typeof data];
      if (raw) {
        const hashed = sha256.hash(raw); // *
        (data[
          "search" as keyof typeof data
        ] as string) = `${raw}&hash=${hashed}`;
        console.log(data);
      }
    }
    console.log("overrided!", args[0]);
    historyBase.push(...args);
  }
};

export default history;

* Note: The useSha256 hook won't work here for this, but since I wasn't able to find any NPM package that provided this hook I am assuming this is a local custom hook. If this is the case then import the object the hook was previously.

Import the low-level base Router component from react-router-dom and your custom history object and pass history as a prop.

Example:

import { StrictMode } from "react";
import * as ReactDOMClient from "react-dom/client";
import { Router } from "react-router-dom";
import history from './history';
import App from "./App";

const rootElement = document.getElementById("root");
const root = ReactDOMClient.createRoot(rootElement);

root.render(
  <StrictMode>
    <Router history={history}>
      <App />
    </Router>
  </StrictMode>
);

At this point the router is using your history object in it's context, so all navigation actions will use it. This means not only directly accessing history in nested children, but Link and other components that take a To object argument as well.

Example:

import { Link, useHistory } from "react-router-dom";

export default function App() {
  const history = useHistory();

  const handler = () => {
    history.push({
      pathname: "/test",
      search: "?....."
    });
  };

  return (
    <div className="App">
      ...
      <ul>
        ...
        <li>
          <Link to={{ pathname: "/foo", search: "?....." }}>
            Foo
          </Link>
        </li>
      </ul>
      <button type="button" onClick={handler}>
        Navigate
      </button>
    </div>
  );
}

Edit is-possible-to-override-history-push-method-of-react-router-dom

enter image description here

  • Related