Chrome 中的路由用 React 编写的扩展
Routing in Chrome Extension written in React
我想要 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 做什么路由?
虽然您不想为您的扩展程序使用浏览器(或哈希)历史记录,但您可以使用内存历史记录。内存历史记录复制浏览器历史记录,但维护自己的历史记录堆栈。
import { createMemoryHistory } from 'history'
const history = createMemoryHistory()
对于只有两个页面的扩展,使用 React Router 是多余的。在状态中维护一个值来描述要呈现哪个 "page" 并使用开关或 if/else 语句仅呈现正确的页面组件会更简单。
render() {
let page = null
switch (this.state.page) {
case 'home':
page = <Home />
break
case 'user':
page = <User />
break
}
return page
}
我通过使用单个路由而不是嵌套路由解决了这个问题。问题出在另一个地方...
此外,我创建了一个问题:https://github.com/ReactTraining/react-router/issues/4309
我知道这个 post 很旧。尽管如此,我还是会在这里留下我的答案,以防万一有人还在寻找它,并希望得到一个快速的答案来修复他们现有的路由器。
在我的例子中,我只是从 BrowserRouter
切换到 MemoryRouter
。不需要额外的 memory
包!
import { MemoryRouter as Router } from 'react-router-dom';
ReactDOM.render(
<React.StrictMode>
<Router>
<OptionsComponent />
</Router>
</React.StrictMode>,
document.querySelector('#root')
);
中尝试其他适合您的方法
这是我刚刚找到的一个非常轻量级的解决方案。我刚刚尝试过 - 简单而高效:react-chrome-extension-router
我只需要使用 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;
一个现代的轻量级选项已经出现在包 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>
);
我想要 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 做什么路由?
虽然您不想为您的扩展程序使用浏览器(或哈希)历史记录,但您可以使用内存历史记录。内存历史记录复制浏览器历史记录,但维护自己的历史记录堆栈。
import { createMemoryHistory } from 'history'
const history = createMemoryHistory()
对于只有两个页面的扩展,使用 React Router 是多余的。在状态中维护一个值来描述要呈现哪个 "page" 并使用开关或 if/else 语句仅呈现正确的页面组件会更简单。
render() {
let page = null
switch (this.state.page) {
case 'home':
page = <Home />
break
case 'user':
page = <User />
break
}
return page
}
我通过使用单个路由而不是嵌套路由解决了这个问题。问题出在另一个地方...
此外,我创建了一个问题:https://github.com/ReactTraining/react-router/issues/4309
我知道这个 post 很旧。尽管如此,我还是会在这里留下我的答案,以防万一有人还在寻找它,并希望得到一个快速的答案来修复他们现有的路由器。
在我的例子中,我只是从 BrowserRouter
切换到 MemoryRouter
。不需要额外的 memory
包!
import { MemoryRouter as Router } from 'react-router-dom';
ReactDOM.render(
<React.StrictMode>
<Router>
<OptionsComponent />
</Router>
</React.StrictMode>,
document.querySelector('#root')
);
中尝试其他适合您的方法
这是我刚刚找到的一个非常轻量级的解决方案。我刚刚尝试过 - 简单而高效:react-chrome-extension-router
我只需要使用 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;
一个现代的轻量级选项已经出现在包 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>
);