如何通过 React Router 传递状态?
Posted
技术标签:
【中文标题】如何通过 React Router 传递状态?【英文标题】:How do I pass state through React_router? 【发布时间】:2017-05-18 21:01:28 【问题描述】:这是给我带来麻烦的文件:
var Routers = React.createClass(
getInitialState: function()
return
userName: "",
relatives: []
,
userLoggedIn: function(userName, relatives)
this.setState(
userName: userName,
relatives: relatives,
)
,
render: function()
return (
<Router history=browserHistory>
<Route path="/" userLoggedIn=this.userLoggedIn component=LogIn/>
<Route path="feed" relatives=this.state.relatives userName=this.state.userName component=Feed/>
</Router>
);
);
我正在尝试通过路由将新的this.state.relatives
和this.state.userName
传递到我的“feed”组件中。但我收到此错误消息:
警告:[react-router] 你不能改变;这将是 忽略
我知道为什么会发生这种情况,但不知道我应该如何将状态传递给我的“提要”组件。在过去的 5 个小时里,我一直在尝试解决这个问题,我变得非常绝望!
请帮忙! 谢谢
解决方案:
下面的答案很有帮助,我感谢作者,但他们不是最简单的方法。 在我的情况下,最好的方法是这样的: 当您更改路线时,您只需像这样附加一条消息:
browserHistory.push(pathname: '/pathname', state: message: "hello, im a passed message!");
或者如果您通过链接进行操作:
<Link
to=
pathname: '/pathname',
state: message: 'hello, im a passed message!'
/>
来源:https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/location.md
在您尝试访问的组件中,您可以像这样访问变量,例如:
componentDidMount: function()
var recievedMessage = this.props.location.state.message
,
我希望这会有所帮助! :)
【问题讨论】:
查看此答案***.com/a/29720488/444829<Route>
来自旧版本,因此您将继续使用component
属性,而不是该答案使用的handler
属性。
会写一个带有解释的答案。
nononono 不要!我已经找到了解决方案!我在找到解决方案后立即删除了我所做的评论,但不幸的是,你似乎已经把它变红了。非常感谢:)
@PaulS 再次想到我一直在努力学习,而我发现的解决方案似乎只是一个半解决方案。你介意解释一下你提到的解决方案在我的场景中会是什么样子吗?真的很棒! :)
随时将您更新的解决方案作为答案,然后将您的答案标记为正确答案。
【参考方案1】:
tl;dr 在管理需要在整个应用程序中访问的状态时,最好的办法是使用像 redux
或 mobx
这样的存储。这些库允许您的组件连接/观察状态并随时了解任何状态更改。
什么是<Route>
?
你不能通过 <Route>
组件传递 props 的原因是它们不是真正的组件,因为它们不渲染任何东西。相反,它们用于构建路由配置对象。
这意味着:
<Router history=browserHistory>
<Route path='/' component=App>
<Route path='foo' component=Foo />
</Route>
</Router>
等价于:
<Router history=browserHistory routes=
path: '/',
component: App,
childRoutes: [
path: 'foo',
component: Foo
]
/>
路线仅在初始装载时评估,这就是为什么您不能将新道具传递给它们的原因。
静态道具
如果您有一些静态道具想要传递给您的商店,您可以创建自己的高阶组件,将它们注入商店。不幸的是,这仅适用于静态道具,因为如上所述,<Route>
s 仅被评估一次。
function withProps(Component, props)
return function(matchProps)
return <Component ...props ...matchProps />
class MyApp extends React.Component
render()
return (
<Router history=browserHistory>
<Route path='/' component=App>
<Route path='foo' component=withProps(Foo, test: 'ing' ) />
</Route>
</Router>
)
使用location.state
location.state
是在导航时在组件之间传递状态的便捷方式。然而,它有一个主要的缺点,那就是状态仅在您的应用程序中导航时存在。如果用户点击指向您网站的链接,则该位置不会附加任何状态。
使用商店
那么如何将数据传递给路由的component
s?一种常见的方法是使用像redux
或mobx
这样的商店。使用redux
,您可以使用更高阶的组件将您的组件connect
存储到商店。然后,当你的路由的component
(它实际上是以你的路由组件作为其子组件的 HOC)渲染时,它可以从存储中获取最新信息。
const Foo = (props) => (
<div>props.username</div>
)
function mapStateToProps(state)
return
value: state.username
;
export default connect(mapStateToProps)(Foo)
我对@987654340@ 不是特别熟悉,但据我了解,它可以更容易设置。使用 redux
、mobx
或其他状态管理之一是在整个应用程序中传递状态的好方法。
注意:您可以在此处停止阅读。以下是传递状态的合理示例,但您可能应该只使用存储库。
没有商店
如果您不想使用商店怎么办?你运气不好?不可以,但您必须使用 React 的实验性功能:context
。为了使用context
,您的父组件之一必须显式定义getChildContext
方法以及childContextTypes
对象。任何想要通过context
访问这些值的子组件都需要定义一个contextTypes
对象(类似于propTypes
)。
class MyApp extends React.Component
getChildContext()
return
username: this.state.username
MyApp.childContextTypes =
username: React.PropTypes.object
const Foo = (props, context) => (
<div>context.username</div>
)
Foo.contextTypes =
username: React.PropTypes.object
您甚至可以编写自己的高阶组件,自动将context
值作为<Route>
component
s 的props 注入。这将是一个“穷人的商店”。您可以让它工作,但与使用上述商店库之一相比,效率很可能会降低,并且存在更多错误。
React.cloneElement
呢?
还有另一种方法可以为<Route>
的component
提供道具,但它一次只能工作一个级别。本质上,当 React Router 基于当前路由渲染组件时,它首先为嵌套最深的匹配 <Route>
创建一个元素。然后,在为下一个嵌套最深的<Route>
创建元素时,它会将该元素作为children
属性传递。这意味着在第二个组件的render
方法中,您可以使用React.cloneElement
克隆现有的children
元素并为其添加额外的道具。
const Bar = (props) => (
<div>These are my props: JSON.stringify(props)</div>
)
const Foo = (props) => (
<div>
This is my child:
props.children && React.cloneElement(props.children, username: props.username )
</div>
)
这当然很乏味,尤其是如果您需要通过多个级别的<Route>
component
s 传递此信息。您还需要在基础 <Route>
组件(即 <Route path='/' component=Base>
)中管理您的状态,因为您无法从 <Router>
的父组件中注入状态。
【讨论】:
问题是改变路由本身的状态 请注意,React.PropTypes
自 React v15.5 以来已移至不同的包中。请改用“prop-types”库:npmjs.com/package/prop-types
那么为什么LocationDescriptorObject接口中有一个.state属性呢?这令人困惑 - 我在文档中找不到任何内容......我的意思是我无论如何都在使用 redux,但它的意图是什么?
@YannicHamann location.state 来自浏览器(history.pushState/replaceState 的第一个参数是与位置关联的可序列化状态)并带有警告,例如当您直接导航到页面时它为 null .我发现 location.state 最适合临时数据,例如登录后导航到的 URL,而“真实”状态最好保留在其他地方。
这在 2022 年已经过时了。它也是固执己见和误导的。单独使用全局存储与通过导航传递状态具有相同的问题,并且作者没有表明状态需要“在整个应用程序中可访问”。他们只需要在导航时传递状态,这并不需要全局存储。【参考方案2】:
我知道回答这个问题可能会迟到,但是对于将来对此感到疑惑的任何人,您可以这样做:
export default class Routes extends Component
constructor(props)
super(props);
this.state = config: 'http://localhost' ;
render()
return (
<div>
<BrowserRouter>
<Switch>
<Route path="/" exact component=App />
<Route path="/lectures" exact render=() => <Lectures config=this.state.config /> />
</Switch>
</BrowserRouter>
</div>
);
通过这种方式,您可以访问 Lecture 组件中的配置道具。 这是围绕这个问题的一点点,但首先它是一个很好的接触! :)
【讨论】:
【参考方案3】:一旦安装了路由器组件,您就无法更改 React-router 的状态。您可以编写自己的 html5 路由组件并监听 url 的变化。
class MyRouter extend React.component
constructor(props,context)
super(props,context);
this._registerHashEvent = this._registerHashEvent.bind(this)
_registerHashEvent()
window.addEventListener("hashchange", this._hashHandler.bind(this), false);
...
...
render()
return ( <div> <RouteComponent /> </div>)
【讨论】:
我认为这并不能真正回答原始问题。这如何提供将路线与状态联系起来的能力?【参考方案4】:对于像我这样的人,
你也可以正常渲染这个:
import
BrowserRouter as Router,
Router,
Link,
Switch
from 'react-router-dom'
<Router>
<Switch>
<Link to='profile'>Profile</Link>
<Route path='profile'>
<Profile data=this.state.username />
</Route>
<Route component=PageNotFound />
</Switch>
</Router>
这对我有用!
【讨论】:
【参考方案5】:请注意,如果您使用的是query string
,则需要添加search
。
例如:
key: 'ac3df4', // not with HashHistory!
pathname: '/somewhere',
search: '?some=search-string',
hash: '#howdy',
state:
[userDefined]: true
花了大约 20 分钟才弄清楚为什么我的路线没有被渲染?
【讨论】:
以上是关于如何通过 React Router 传递状态?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 onClick 方法通过 react-router 传递道具
React + Redux + Router - 我应该为所有页面/组件使用一个状态/存储吗?
如何使用 react-router 通过 Route 渲染传递 redux 商店道具?