React: Using NavLink in a shared component library imported as a node_module

Viewed 579

I have a working shared component library that I import into my front end app as a node_module using package.json.

I have built a PaginationLinks component that uses NavLink:

PaginationLinks.js (in shared component library)

import { NavLink } from 'react-router-dom';

const PaginationLinks = {
  return (
    <Container>
      ...
      <NavLink to={"/"}>Home</NavLink>
    </Container>
  );
};

export default PaginationLinks;

In my front end app, I have react-router and all of that set up already in my working app:

routes.js

import { Route, Switch, Redirect } from 'react-router';
import React from 'react';
import { history } from './redux/store';
import { ConnectedRouter } from 'connected-react-router';
...

function App() {
  return (
    <ConnectedRouter history={history}>
      <Switch>
        <BasePage>
          <Switch>
            <Route
              exact
              path="/"
              component={HomePage}
            />
            ...
          </Switch>
        </BasePage>
      </Switch>
    </ConnectedRouter>
  );
}

FYI this is already an app where I have existing routes and import NavLink with no problem.

However, when I try to import my component into my app, it is complaining that my NavLink is not inside a router:

Error: Invariant failed: You should not use <NavLink> outside a <Router>

import React from 'react';
import { NavLink } from 'react-router-dom';
import PaginationLinks from '@my-lib/ui/components/PaginationLinks';
import H1 from '@my-lib/ui/components/H1';

const HomePage = () => (
  <div>
    <H1>hello</H1> // this works
    <NavLink to="/somewhere">somewhere</NavLink> // this works
    <PaginationLinks /> // this breaks the app
  </div>;

)

export default HomePage;

How would I use NavLink inside a shared component library? It doesn't make sense to wrap PaginationLinks inside of a Router in my shared component library.

1 Answers

I fixed it by using peerDependencies + moving those dependenecies into devDependencies. My assumption is that node will scan for dependencies in this order:

  1. dependencies in my shared component lib's package.json
  2. dependencies in my React app

therefore I had to move the react routing libs into devDependencies so that I could still run my storybook server locally and still have the shared component node_module load properly in production in my react app.

Here's my package.json

  "name": "mypackage",
  "version": "0.6.3",
  "dependencies": {
    ...
  },
  "peerDependencies": {
    "react": "^16.13.1",
    "styled-components": "^4.4.1",
    "react-dom": "^16.12.0",
    "react-router": "^5.2.0",
    "react-router-dom": "^5.2.0"
  },
  "scripts": {
    "start": "start-storybook -p 9009",
    "eslint": "eslint --ignore-path .gitignore ./",
    "eslint:fix": "eslint --fix --ignore-path .gitignore ./",
    "prettier": "prettier -c ./",
    "prettier:fix": "prettier --write ./"
  },
  ...
  "devDependencies": {
    ...
    "react": "^16.13.1",
    "styled-components": "^4.4.1",
    "react-dom": "^16.12.0",
    "react-router": "^5.2.0",
    "react-router-dom": "^5.2.0"
  },
  "husky": {
    "hooks": {
      "pre-commit": "pretty-quick --staged",
      "pre-push": "npm run eslint"
    }
  }
}
Related