Skip to content

Adding "useLink" hooks #7390

@the-spyke

Description

@the-spyke

The Link component has some useful logic inside. I didn't see other ways to reuse it, but to render a <Link />. It isn't very convenient when you use link/anchor components from another libraries which usually implies using as props to replace underlying component. Sometimes it also gives you troubles with filtering additional props and sometimes requires hacks. I think it could be done without additional overhead and those forwardRefs in the Link's code.

I've tried to do a couple of additional hooks, that translate this (with broken icon without additional work):

<Anchor label="MyApp" icon={Icons.Home} as={Link} to="/home" />

Into this (with working everyting):

<Anchor label="MyApp" icon={Icons.Home} {...useLink("/home")} />

The code is quite simple (also allows to get normalized href and onClick handler separately) and uses parts from the packages/react-router-dom/modules/Link.js:

import {
  resolveToLocation,
  normalizeToLocation
} from "./utils/locationUtils.js";

const useHref = to => {
  const history = useHistory();
  const location = useLocation();

  const resolvedLocation = resolveToLocation(to, location);
  const normalizedLocation = normalizeToLocation(resolvedLocation, location);

  return normalizedLocation ? history.createHref(normalizedLocation) : "";
};

const useClick = (to, replace = false) => {
  const history = useHistory();
  const location = useLocation();

  const resolvedLocation = resolveToLocation(to, location);
  const method = replace ? history.replace : history.push;

  return useCallback(event => {
    if (
      !event.defaultPrevented && // onClick prevented default
      event.button === 0 && // ignore everything but left clicks
      !isModifiedEvent(event) // ignore clicks with modifier keys
    ) {
      event.preventDefault();

      method(resolvedLocation);
    }
  }, [resolvedLocation, method]);
};

const useLink = (to, replace = false) => {
  return {
    href: useHref(to),
    onClick: useClick(to, replace),
  };
};

You get the same href with useHref as Link passes down and onClick as combined logic from Link and LinkAnchor respectively with useClick.

Finally, useLink gives you and object to spread into a component whatever you use for displaying an anchor/link.

If this sounds interesting, I can make PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions