用 React 编写的 Chrome 扩展中的路由

Posted

技术标签:

【中文标题】用 React 编写的 Chrome 扩展中的路由【英文标题】:Routing in Chrome Extension written in React 【发布时间】:2017-05-11 03:57:50 【问题描述】:

我希望 Chrome 扩展程序中有 2 个页面。例如:第一个(默认)页面包含用户列表,第二个页面包含该用户的操作。

我想通过单击用户(在我的情况下为ClickableListItem)来显示第二页。我使用 React 和 React 路由器。这是我拥有的组件:

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>
  );


我还尝试将ClickableListItem 包装成Link 组件(来自react-router),但它什么也没做。

也许问题是 Chrome 扩展没有他们的browserHistory...但是我在控制台中没有看到任何错误...

如何使用 React 进行路由?

【问题讨论】:

handleOnClick 在我单击项目时调用,我可以看到控制台消息 确实,工具栏弹出窗口无法导航。只需显示/隐藏 DOM 元素。还要确保查看正确的控制台(扩展有 3 种类型)。 @wOxxOm 不,可以导航!使用 react-router 或者,正如@Paul 回答的那样,使用 createMemoryHistory 我在经典含义中使用了 navigation,而不是特定于 React(它只是按照我的建议通过切换/添加 DOM 元素来模仿导航)。跨度> 【参考方案1】:

虽然您不想为扩展程序使用浏览器(或哈希)历史记录,但您可以使用内存历史记录。内存历史复制浏览器历史,但维护自己的历史堆栈。

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

对于只有两个页面的扩展,使用 React Router 是多余的。在 state 中维护一个值会更简单,该值描述要呈现哪个“页面”并使用 switch 或 if/else 语句仅呈现正确的页面组件。

render() 
  let page = null
  switch (this.state.page) 
  case 'home':
    page = <Home />
    break
  case 'user':
    page = <User />
    break
  
  return page

【讨论】:

我稍后试试! 这是标准做法吗?在 Chrome 扩展程序中进行路由应该很常见【参考方案2】:

我知道这篇文章已经过时了。不过,我会在此处留下我的答案,以防有人仍在寻找它并想要快速回答以修复他们现有的路由器。

就我而言,我只是从BrowserRouter 切换到MemoryRouter。无需额外的memory 包,它就像魅力一样工作!

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

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

您可以在ReactRouter Documentation中尝试其他适合您的方法

【讨论】:

嗨,Snek,你能解释一下如何在没有 path="" 的情况下切换到不同的路线吗? @joshmillgate “切换到没有路径的不同路线”是什么意思?你的意思是&lt;Route render=something&gt; 没有路径?我不认为那是一回事。或者您的意思是在没有&lt;Link&gt; 的情况下切换到不同的路线?如果是这种情况,您可以使用&lt;Route&gt; 的渲染道具history 属性或只使用&lt;Redirect&gt;。如果需要,请随时与我联系。 @SnekNOTSnake 这行得通,但是“返回”操作不起作用:/ 知道如何处理吗?【参考方案3】:

我通过使用单路由而不是嵌套路由解决了这个问题。问题出在别的地方……

另外,我创建了一个问题:https://github.com/ReactTraining/react-router/issues/4309

【讨论】:

太糟糕了,维护者锁定了这个问题。 :-/【参考方案4】:

我只需要使用createMemoryHistory 而不是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;

【讨论】:

【参考方案5】:

这是我刚刚找到的一个非常轻量级的解决方案。我刚刚尝试过 - 简单而高效:react-chrome-extension-router

【讨论】:

【参考方案6】:

一个现代轻量级选项出现在包wouter

您可以创建自定义挂钩以根据哈希更改路由。

见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>
);

【讨论】:

以上是关于用 React 编写的 Chrome 扩展中的路由的主要内容,如果未能解决你的问题,请参考以下文章

如何从 JS 开发控制台访问用 Chrome 扩展编写的功能?

React.js Chrome 扩展 - 如何将 Background.js 中的数据存储在 React 内部的变量中?

如何使用具有多个页面和入口点的 React 和 TypeScript 设置 chrome 扩展?

如何在运行 React 的 Chrome 扩展中运行 Redux DevTools 扩展?

用Chrome浏览器配置react开发者工具

Chrome 扩展(内容脚本)+ React:从 DOM 获取 React 组件?