我正在使用react-router-dom
Link
和NavLink
v5,并且想要短路to
参数值以传递给onClick
。
这是我的情况:
在我的应用程序中 - 到目前为止,仅
to
参数用于 React Link 和 NavLink。
但是,我有一个新要求,即我需要在单击“链接”或“导航链接”时向外部 iFrame 发送一些事件。
到目前为止我的代码是这样的:
const addVolumeLink = location => ({
pathname: location.pathname + "/add-volume",
state: {
from: location.pathname
}
});
<Link to={addVolumeLink}>New volume</Link>
但是,当用户单击“新卷”时,我还需要向外部 iFrame 发送一个事件。因此,我天真地通过添加
onClick
监听器来更改此代码,如下所示。
const addVolumeLink = location => ({
pathname: location.pathname + "/add-volume",
state: {
from: location.pathname
}
});
export const nagivateToParentiFrame = (payload) => {
window.parent.postMessage({
type: 'SERVICE:NAVIGATE',
payload,
}, "*")
};
<Link to={addVolumeLink}
onClick={() => nagivateToParentiFrame({
pathname: `${window.location.pathname}/add-volume`,
state: {from: window.location.pathname}})}>
New volume
</Link>
我正在寻找:是否有办法将
to
参数短路到 onClick。 (注意:这里是一个使用 location 的函数调用。可以是函数调用,也可以是对象)。
原因:我需要在代码中写100处这个onClick。
所以我正在考虑拥有自己的 Link 组件,只需替换 import
而不是到处写这个 onClick (因为我的路径名和状态应该是相同的)。
我尝试过类似的事情(但没有成功):
// 不工作的组件。
import {Link} from "react-router-dom"
const nagivateToParentiFrame = (payload) => {
window.parent.postMessage({
type: 'SERVICE:NAVIGATE',
payload,
}, "*")
};
export const StyledLinkWithIframeEvent = ({ children, className, style, color, type, large, disabled, tooltip, to, ...rest }) => {
return <Link
to={to}
onClick={() => nagivateToParentiFrame(to)}
children={children}
className={className}
style={style}
color={color}
type={type}
large={large}
disabled={disabled}
tooltip={tooltip}
rest={rest}>
</Link>
}
组件的用途:
import {StyledLinkWithIframeEvent as StyledLink} from "./myLink"
const addVolumeLink = location => ({
pathname: location.pathname + "/add-volume",
state: {
from: location.pathname
}
});
const myMainComponent = () => {
return (<StyledLink to={addVolumeLink}>
New volume
</StyledLink>);
}
创建一个自定义链接组件,添加自己的
onClick
处理程序,该处理程序调用您的 navigateToParentiFrame
函数,并传递所传递的 to
属性的结果。
export const navigateToParentiFrame = (payload) => {
window.parent.postMessage({
type: 'SERVICE:NAVIGATE',
payload,
}, "*")
};
import { Link as BaseLink, useLocation } from 'react-router-dom';
import { navigateToParentiFrame } from '../path/to/navigateToParentiFrame';
const Link = props => {
const location = useLocation();
return (
<BaseLink
{...props}
onClick={navigateToParentiFrame.bind(
null,
typeof props.to === "function"
? props.to(location)
: props.to
)}
>
{props.children}
</BaseLink>
);
};
const addVolumeLink = location => ({
...location,
pathname: location.pathname + "/add-volume",
state: {
...location.state,
from: location.pathname,
}
});
<Link to={addVolumeLink}>New volume</Link>
const {
BrowserRouter: Router,
Switch,
Route,
Link: BaseLink,
useLocation,
} = ReactRouterDOM;
const navigateToParentiFrame = (payload) => {
console.log("window.parant.postMessage", {
type: 'SERVICE:NAVIGATE',
payload,
}, "*");
};
const Link = props => {
const location = useLocation();
return (
<BaseLink
{...props}
onClick={navigateToParentiFrame.bind(
null,
typeof props.to === "function"
? props.to(location)
: props.to
)}
>
{props.children}
</BaseLink>
);
};
const addVolumeLink = location => ({
...location,
pathname: location.pathname + "add-volume",
state: {
...location.state,
from: location.pathname,
}
});
//<Link to={addVolumeLink}>New volume</Link>
const App = () => {
return (
<React.Fragment>
<ul>
<li>
<BaseLink to="/">Home</BaseLink>
</li>
<li>
<Link to={addVolumeLink}>New volume</Link>
</li>
</ul>
<Switch>
<Route path="/add-volume" render={() => <h1>Add Volume</h1>} />
<Route path="/" render={() => <h1>Home</h1>} />
</Switch>
</React.Fragment>
);
}
const rootElement = document.getElementById("root");
const root = ReactDOM.createRoot(rootElement);
root.render(
<React.StrictMode>
<Router basename="/js">
<App />
</Router>
</React.StrictMode>
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-router-dom/5.3.4/react-router-dom.min.js" integrity="sha512-XJ25BbjmZQpaGkOJaDFXVJqfsBebv2aDLsBF3qT6zoC/gVj7XLuefNRzcgmlc5admYuODaYDrap8jzVyOsYFrw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div id="root" />