Routing in Chrome Extension written in React
Asked Answered
H

8

16

I want 2 pages in my Chrome extension. For example: first(default) page with list of users and second with actions for this user.

I want to display second page by clicking on user(ClickableListItem in my case). I use React and React Router. Here the component in which I have:

class Resents extends React.Component {
constructor(props) {
  super(props);
  this.handleOnClick = this.handleOnClick.bind(this);
}
handleOnClick() {
  console.log('navigate to next page');
  const path = '/description-view';
  browserHistory.push(path);
}
render() {
  const ClickableListItem = clickableEnhance(ListItem);
  return (
    <div>
      <List>
        <ClickableListItem
          primaryText="Donald Trump"
          leftAvatar={<Avatar src="img/some-guy.jpg" />}
          rightIcon={<ImageNavigateNext />}
          onClick={this.handleOnClick}
        />
      // some code missed for simplicity
      </List>
    </div>
  );
}
}

I also tried to wrap ClickableListItem into Link component(from react-router) but it does nothing.

Maybe the thing is that Chrome Extensions haven`t their browserHistory... But I don`t see any errors in console...

What can I do for routing with React?

Hadji answered 26/12, 2016 at 19:20 Comment(4)
handleOnClick called when I click on Item, I can see console messageHadji
Indeed, the toolbar popup cannot be navigated. Simply show/hide DOM elements. Also make sure to look at the correct console (extensions have 3 types).Pachalic
@wOxxOm no, navigation is possible! Using react-router or, as @Paul answered, using createMemoryHistoryHadji
I've used navigation in the classic meaning, not React-specific (it just imitates navigation by toggling/adding DOM elements just as I suggested).Pachalic
H
5

I solved this problem by using single routes instead of nested. The problem was in another place...

Also, I created an issue: https://github.com/ReactTraining/react-router/issues/4309

Hadji answered 28/12, 2016 at 8:58 Comment(1)
Too bad the maintainers locked the issue. :-/Arta
D
37

I know this post is old. Nevertheless, I'll leave my answer here just in case somebody still looking for it and want a quick answer to fix their existing router.

In my case, I get away with just switching from BrowserRouter to MemoryRouter. It works like charm without a need of additional memory package!

import { MemoryRouter as Router } from 'react-router-dom';

ReactDOM.render(
    <React.StrictMode>
        <Router>
            <OptionsComponent />
        </Router>
    </React.StrictMode>,
    document.querySelector('#root')
);

You can try other methods, that suits for you in the ReactRouter Documentation

Demulcent answered 1/8, 2020 at 18:34 Comment(6)
Hey Snek, can you explain how you would switch to a different route without path=""?Priory
@Priory what do you mean by "Switch to different route without path"? You mean <Route render={something}> without path? I don't think that's even a thing. Or you mean switch to different route without <Link>? If that's the case, you can use the <Route>'s render props history property or just use <Redirect>. Feel free to contact me if you want.Demulcent
@Demulcent this works, but then the "go back" actions doesn't work :/ Any idea how to handle this?Desma
I know this is an old post but still, this can use for someone. I use v6 of "react-router-dom". its works perfectly for me. Check the docs here reactrouter.com/docs/en/v6Catharina
@DanielprabhakaranN I'm trying to do the same with react router v6 but can't seem to make it work. How did you do this?Kuhlman
You can't even imagine how much I love you right now.Docent
C
13

While you wouldn't want to use the browser (or hash) history for your extension, you could use a memory history. A memory history replicates the browser history, but maintains its own history stack.

import { createMemoryHistory } from 'history'
const history = createMemoryHistory()

For an extension with only two pages, using React Router is overkill. It would be simpler to maintain a value in state describing which "page" to render and use a switch or if/else statements to only render the correct page component.

render() {
  let page = null
  switch (this.state.page) {
  case 'home':
    page = <Home />
    break
  case 'user':
    page = <User />
    break
  }
  return page
}
Correia answered 26/12, 2016 at 23:56 Comment(2)
I`ll try it later!Hadji
Is this standard practice? It should be pretty common to have routing in Chrome ExtensionsTeenyweeny
H
5

I solved this problem by using single routes instead of nested. The problem was in another place...

Also, I created an issue: https://github.com/ReactTraining/react-router/issues/4309

Hadji answered 28/12, 2016 at 8:58 Comment(1)
Too bad the maintainers locked the issue. :-/Arta
T
1

This is a very lightweight solution I just found. I just tried it - simple and performant: react-chrome-extension-router

Temperance answered 16/4, 2021 at 15:5 Comment(0)
P
1

I just had to use createMemoryHistory instead of createBrowserHistory:

import React from "react";
import ReactDOM from "react-dom";
import { Router, Switch, Route, Link } from "react-router-dom";
import { createMemoryHistory } from "history";

import Page1 from "./Page1";
import Page2 from "./Page2";

const history = createMemoryHistory();

const App: React.FC<{}> = () => {
  return (
    <Router history={history}>
      <Switch>
        <Route exact path="/">
          <Page1 />
        </Route>
        <Route path="/page2">
          <Page2 />
        </Route>
      </Switch>
    </Router>
  );
};

const root = document.createElement("div");
document.body.appendChild(root);
ReactDOM.render(<App />, root);
import React from "react";
import { useHistory } from "react-router-dom";

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

  return (
    <button onClick={() => history.push("/page2")}>Navigate to Page 2</button>
  );
};

export default Page1;

Photophobia answered 15/9, 2021 at 15:5 Comment(0)
O
1

A modern lightweight option has presented itself with the package wouter.

You can create a custom hook to change route based on the hash.

see wouter docs.

import { useState, useEffect } from "react";
import { Router, Route } from "wouter";

// returns the current hash location in a normalized form
// (excluding the leading '#' symbol)
const currentLocation = () => {
  return window.location.hash.replace(/^#/, "") || "/";
};

const navigate = (to) => (window.location.hash = to);

const useHashLocation = () => {
  const [loc, setLoc] = useState(currentLocation());

  useEffect(() => {
    // this function is called whenever the hash changes
    const handler = () => setLoc(currentLocation());

    // subscribe to hash changes
    window.addEventListener("hashchange", handler);
    return () => window.removeEventListener("hashchange", handler);
  }, []);

  return [loc, navigate];
};

const App = () => (
  <Router hook={useHashLocation}>
    <Route path="/about" component={About} />
    ...
  </Router>
);
Osmic answered 6/1, 2022 at 7:23 Comment(0)
O
1

Try using HashRouter instead of BrowserRouter

Here is index.js

root.render(
  <StrictMode>
    <Provider store={store} >
      <PersistGate persistor={persistor}>
        <HashRouter>
          <ChakraProvider theme={theme}>
            <ColorModeScript />
            <App />
          </ChakraProvider>
        </HashRouter>
      </PersistGate>
    </Provider>

  </StrictMode>
);

And here is app.js

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/about" element={<About />} />
</Routes>
Overweight answered 7/2 at 15:52 Comment(0)
S
0

I solved this problem by running the npm eject and creating a second home.html file.

I made a starter code for anyone who wants to develop a chrome extension using react in the following Github repo react-chrome-extension-template

The starter code contains both popup page index.html and home page home.html and navigation button in the popup to the home page.

Stride answered 31/5, 2023 at 5:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.