javascript 反应路由器仅模态路由
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28795085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
React router modal-only routes
提问by Roman K
I do have a public and a private area in my app and i want to be able to show the login modal dialog everywhere in the public view. The modal should have its own route. A second use case would be a profile modal in the private area.
我的应用程序中有一个公共区域和一个私人区域,我希望能够在公共视图中的任何地方显示登录模式对话框。模态应该有自己的路线。第二个用例是私人区域中的配置文件模式。
The problem is that the current view in the background would disappear when the modal is shown because the modal is not a child of the current views route.
问题是当显示模态时,背景中的当前视图会消失,因为模态不是当前视图路由的子级。
Since i do not want to add the same modal to every possible view route, here is the question: Is it possible to decouple modal routes from its parent routes and show them everywhere in the app without the main content rendering? What is the best approach for this? I've found this issuebut is seems not to be the same problem.
由于我不想为每个可能的视图路由添加相同的模态,这里有一个问题:是否可以将模态路由与其父路由分离并在应用程序中的任何地方显示它们而无需主要内容渲染?最好的方法是什么?我发现了这个问题,但似乎不是同一个问题。
A browser refresh on the modal route would render nothing in the background but that is a problem i could live with.
模式路由上的浏览器刷新不会在后台渲染任何内容,但这是我可以忍受的问题。
采纳答案by Michelle Tilley
I think your best option is probably to utilize either the hidden state
, or query strings (for permalinks), or both, especially if a modal (e.g. a login modal) could be displayed on any page. Just in case you're not aware, React Router exposes the state
part of the history API, allowing you to store data in the user's history that's not actually visible in the URL.
我认为您最好的选择可能是使用 hiddenstate
或查询字符串(用于永久链接),或两者兼而有之,特别是如果模式(例如登录模式)可以显示在任何页面上。以防万一您不知道,React Router 公开了state
历史 API的一部分,允许您将数据存储在用户的历史记录中,而这些数据实际上在 URL 中是不可见的。
Here's a set of routes I have in mind; you can jump straight into the working example on JSBinif you want. You can also view the resulting example app in its own windowso you can see the URLs changing (it uses the hash location strategy for compatibility with JSBin) and to make sure refreshing works as you'd expect.
这是我想到的一组路线;如果需要,您可以直接跳到JSBin 上的工作示例。您还可以在其自己的窗口中查看生成的示例应用程序,以便您可以看到 URL 的变化(它使用哈希位置策略与 JSBin 兼容)并确保刷新如您所愿。
const router = (
<Router>
<Route component={LoginRedirect}>
<Route component={LocationDisplay}>
<Route path="/" component={ModalCheck}>
<Route path="/login" component={makeComponent("login")} />
<Route path="/one" component={makeComponent("one")} />
<Route path="/two" component={makeComponent("two")} />
<Route path="/users" component={makeComponent("users")}>
<Route path=":userId" component={UserProfileComponent} />
</Route>
</Route>
</Route>
</Route>
</Router>
);
Let's investigate these routes and their components.
让我们研究一下这些路由和它们的组成部分。
First of all, makeComponent
is just a method that takes a string and creates a React component that renders that string as a header and then all its children; it's just a fast way to create components.
首先,makeComponent
它只是一个方法,它接受一个字符串并创建一个 React 组件,该组件将该字符串呈现为标题,然后是它的所有子项;这只是创建组件的一种快速方法。
LoginRedirect
is a component with one purpose: check to see if the path is /login
orif there is a ?login
query string on the current path. If either of these are true, andthe current state does not contain the login
key, it sets the login
key on the state to true
. The route is used if anychild route is matched (that is, the component is always rendered).
LoginRedirect
是一个具有一个目的的组件:检查路径是否存在/login
或?login
当前路径上是否存在查询字符串。如果其中任何一个为真,并且当前状态不包含login
密钥,则将状态上的密钥设置login
为true
。如果路由使用任何孩子的路线匹配(即,分量总是呈现)。
class LoginRedirect extends React.Component {
componentWillMount() {
this.handleLoginRedirect(this.props);
}
componentWillReceiveProps(nextProps) {
this.handleLoginRedirect(nextProps);
}
handleLoginRedirect(props) {
const { location } = props;
const state = location.state || {};
const onLoginRoute = location.query.login || location.pathname === "/login";
const needsStateChange = onLoginRoute && !state.login;
if (needsStateChange) {
// we hit a URL with ?login in it
// replace state with the same URL but login modal state
props.history.setState({login: true});
}
}
render() {
return React.Children.only(this.props.children);
}
}
If you don't want to use query strings for showing the login modal, you can of course modify this component to suit your needs.
如果您不想使用查询字符串来显示登录模式,您当然可以修改此组件以满足您的需要。
Next is LocationDisplay
, but it's just a component I built for the JSBin demo that displays information about the current path, state, and query, and also displays a set of links that demonstrate the app's functionality.
接下来是LocationDisplay
,但它只是我为 JSBin 演示构建的一个组件,它显示有关当前路径、状态和查询的信息,还显示一组演示应用程序功能的链接。
The login state is important for the next component, ModalCheck
. This component is responsible for checking the current state for the login
(or profile
, or potentially any other) keys and displaying the associated modal as appropriate. (The JSBin demo implements a super simple modal, yours will certainly be nicer. :) It also shows the status of the modal checks in text form on the main page.)
登录状态对于下一个组件很重要ModalCheck
。该组件负责检查login
(或profile
,或可能的任何其他)键的当前状态并根据需要显示相关联的模式。(JSBin 演示实现了一个超级简单的模态,你的肯定会更好。:)它还在主页上以文本形式显示模态检查的状态。)
class ModalCheck extends React.Component {
render() {
const location = this.props.location;
const state = location.state || {};
const showingLoginModal = state.login === true;
const showingProfileMoal = state.profile === true;
const loginModal = showingLoginModal && <Modal location={location} stateKey="login"><LoginModal /></Modal>;
const profileModal = showingProfileMoal && <Modal location={location} stateKey="profile"><ProfileModal /></Modal>;
return (
<div style={containerStyle}>
<strong>Modal state:</strong>
<ul>
<li>Login modal: {showingLoginModal ? "Yes" : "No"}</li>
<li>Profile modal: {showingProfileMoal ? "Yes" : "No"}</li>
</ul>
{loginModal}
{profileModal}
{this.props.children}
</div>
)
}
}
Everything else is fairly standard React Router stuff. The only thing to take note of are the Link
s inside LocationDisplay
that show how you can link to various places in your app, showing modals in certain circumstances.
其他一切都是相当标准的 React Router 东西。唯一需要注意的是Link
里面的sLocationDisplay
显示了如何链接到应用程序中的各个位置,在某些情况下显示模态。
First of all, you can of course link (and permalink) to any page asking it to show the login modal by using the login
key in the query string:
首先,您当然可以通过使用login
查询字符串中的键链接(和永久链接)到任何要求它显示登录模式的页面:
<Link to="/one" query={{login: 1}}>/one?login</Link>
<Link to="/two" query={{login: 1}}>/two?login</Link>
You can also, of course, link directly to the /login
URL.
当然,您也可以直接链接到/login
URL。
Next, notice you can explicitly set the state so that a modal shows, and this will notchange the URL. It will, however, persist in the history, so back/forward can be used as you'd expect, and a refresh will show the modal over top the same background page.
接下来,请注意您可以显式设置状态以便显示模式,并且这不会更改 URL。但是,它会保留在历史记录中,因此可以像您期望的那样使用后退/前进,并且刷新将在同一背景页面的顶部显示模态。
<Link to="/one" state={{login: true}}>/one with login state</Link>
<Link to="/two" state={{login: true}}>/two with login state</Link>
You can also link to the currentpage, addinga particular modal.
您还可以链接到当前页面,添加特定模式。
const path = props.location.pathname;
<Link to={path} state={{login: true}}>current path + login state</Link>
<Link to={path} state={{profile: true}}>current path + profile state</Link>
Of course, depending on how you want your app to work, not all of this is applicable or useful. For example, unless a modal is trulyglobal (that is, it can be displayed no matter the route), this may work fine, but for modals like showing the profile of a given user, I'd probably make that a separate route, nesting it in the parent, e.g.:
当然,取决于您希望应用程序如何工作,并非所有这些都适用或有用。例如,除非模态是真正全局的(也就是说,无论路由如何都可以显示),否则这可能会正常工作,但是对于像显示给定用户的个人资料这样的模态,我可能会将其设为单独的路由,将它嵌套在父级中,例如:
<Route path="/users/:id" component={UserPage}>
<Route path="/users/:id/profile" component={UserProfile} />
</Route>
UserProfile
, in this case, would be a component that renders a modal.
UserProfile
在这种情况下,将是一个呈现模态的组件。
Another example where you may want to make a change is storing certain modals in the history; if you don't want to, use replaceState
instead of setState
as appropriate.
您可能想要进行更改的另一个示例是在历史记录中存储某些模态;如果您不想,请使用replaceState
代替setState
。
回答by u5638915
Use shouldComponentUpdate do this will be Very simple
使用 shouldComponentUpdate 这样做会很简单
<Router history={newHistory}>
<Route path="/" component={App}>
<Route path="home" component={Container} >
<IndexRedirect to="home"/>
<Route path="login" component={Authentication}/>
<Route path="home" component={Home}/>
<Route path="post/:id" component={Post}/>
</Route>
</Route>
</Router>
<Link to='/post/123' state={{isModal:true}}/>
<Link to='/home' state={{isModal:false}}/>
<Link to='/login' state={{isModal:true}}/>
Container = React.createClass({
render() {
let isModal = (location.state && location.state.modal);
return (
<div id="MeContainer">
<ModalControlOpen isModal={isModal}>
<Modal returnTo={this.props.location.pathname}>
{this.props.children}
</Modal>
</ModalControlOpen>
<ModalControlClose isModal={isModal}>
{this.props.children}
</ModalControlClose>
</div>
)
}
});
ModalControlOpen = React.createClass({
render(){
if (this.props.isModal) {
return (
this.props.children
)
} else return <div></div>
}
});
ModalControlClose = React.createClass({
shouldComponentUpdate(nextProp){
return !nextProp.isModal
},
render(){
return (
this.props.children
)
}
});