如何通过 React_router 传递状态? [英] How do I pass state through React_router?

查看:33
本文介绍了如何通过 React_router 传递状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是给我带来麻烦的文件:

var Routers = React.createClass({getInitialState: 函数(){返回{用户名: "",亲戚们: []}},用户登录:功能(用户名,亲戚){this.setState({用户名:用户名,亲戚:亲戚,})},渲染:函数(){返回 (<路由器历史={browserHistory}><Route path="/" userLoggedIn={this.userLoggedIn} component={LogIn}/><Route path="feed" relatives={this.state.relatives} userName={this.state.userName} component={Feed}/></路由器>);}});

我正在尝试将新的 this.state.relativesthis.state.userName 通过路由传递到我的提要"组件中.但我收到此错误消息:

<块引用>

警告:[react-router] 你不能改变;这将是忽略

我知道为什么会发生这种情况,但不知道我还应该如何将状态传递给我的提要"组件.在过去的 5 个小时里,我一直在努力解决这个问题,现在我已经非常绝望了!

请帮忙!谢谢

<小时>

解决方案:

下面的答案很有帮助,我感谢 athors,但他们不是最简单的方法.在我的情况下,最好的方法是这样的:当您更改路线时,您只需像这样附加一条消息:

browserHistory.push({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},

我希望这会有所帮助!:)

解决方案

tl;dr 最好的办法是使用像 reduxmobx<这样的商店/code> 管理需要在整个应用程序中访问的状态时.这些库允许您的组件连接到/观察状态并随时了解任何状态更改.

什么是?

你不能通过 组件传递 props 的原因是它们不是真正的组件,因为它们不渲染任何东西.相反,它们用于构建路由配置对象.

这意味着:

<Route path='/' component={App}><Route path='foo' component={Foo}/></路线></路由器>

相当于:

路由仅在初始安装时进行评估,这就是您不能将新的 props 传递给它们的原因.

静态道具

如果您有一些想要传递给商店的静态道具,您可以创建自己的高阶组件,将它们注入商店.不幸的是,这仅适用于静态道具,因为如上所述, 只计算一次.

function withProps(Component, props) {返回函数(matchProps){return <Component {...props} {...matchProps}/>}}class MyApp 扩展了 React.Component {使成为() {返回 (<路由器历史={browserHistory}><Route path='/' component={App}><Route path='foo' component={withProps(Foo, { test: 'ing' })}/></路线></路由器>)}}

使用location.state

location.state 是一种在导航时在组件之间传递状态的便捷方式.但是,它有一个主要缺点,即状态仅在您的应用程序中导航时才存在.如果用户点击了指向您网站的链接,则该位置不会附加任何状态.

使用商店

那么如何将数据传递给路由的component?一种常见的方法是使用像 reduxmobx 这样的 store.使用 redux,您可以使用更高阶的组件将您的组件connect 到商店.然后,当您路由的 component(实际上是将您的路由组件作为其子组件的 HOC)呈现时,它可以从商店中获取最新信息.

const Foo = (props) =>(<div>{props.username}</div>)函数 mapStateToProps(state) {返回 {值:state.username};}导出默认连接(mapStateToProps)(Foo)

我对 mobx 不是特别熟悉,但据我所知,它可以更容易设置.使用 reduxmobx 或其他状态管理之一是在整个应用程序中传递状态的好方法.

<块引用>

注意:您可以在此处停止阅读.下面是传递状态的合理示例,但您可能应该只使用商店库.

没有商店

如果您不想使用商店怎么办?你倒霉了吗?不,但您必须使用 React 的实验性功能:上下文.为了使用 context,您的父组件之一必须显式定义一个 getChildContext 方法以及一个 childContextTypes 对象.任何想要通过 context 访问这些值的子组件都需要定义一个 contextTypes 对象(类似于 propTypes).

class MyApp 扩展 React.Component {getChildContext() {返回 {用户名:this.state.username}}}MyApp.childContextTypes = {用户名:React.PropTypes.object}const Foo = (props, context) =>(<div>{context.username}</div>)Foo.contextTypes = {用户名:React.PropTypes.object}

您甚至可以编写自己的高阶组件,自动注入 context 值作为 component 的道具.这将是一个穷人的商店".您可以让它工作,但很可能比使用上述商店库之一效率低且错误更多.

React.cloneElement 怎么样?

还有另一种方法可以为 component 提供 props,但它一次只能在一个级别上工作.本质上,当 React Router 基于当前路由渲染组件时,它首先为嵌套最深的匹配 创建一个元素.然后,在为下一个嵌套最深的 创建元素时,它将该元素作为 children 道具传递.这意味着在第二个组件的 render 方法中,你可以使用 React.cloneElement 来克隆现有的 children 元素并添加额外的 props 到

const Bar = (props) =>(<div>这些是我的道具:{JSON.stringify(props)}</div>)const Foo = (道具) =>(<div>这是我的孩子:{props.children &&React.cloneElement(props.children, { username: props.username })}

)

这当然很乏味,特别是如果您需要通过多个级别的 component 来传递此信息.您还需要在基本 <Route> 组件(即 <Route path='/' component={Base}>)中管理您的状态,因为您没有办法从 的父组件注入状态.

Here is the file that's causing me trouble:

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

I am trying to pass the new this.state.relatives and this.state.userName through the routes into my "feed"-component. But I'm getting this error message:

Warning: [react-router] You cannot change ; it will be ignored

I know why this happens, but don't know how else i'm supposed to pass the states to my "feed"-component. I've been trying to fix this problem for the past 5 hours and í'm getting quite desperate!

Please help! Thanks


SOLUTION:

The answers below were helpful and i thank the athors, but they were not the easiest way to do this. The best way to do it in my case turned out to be this: When you change routes you just attach a message to it like this:

browserHistory.push({pathname: '/pathname', state: {message: "hello, im a passed message!"}});

or if you do it through a link:

<Link 
    to={{ 
    pathname: '/pathname', 
    state: { message: 'hello, im a passed message!' } 
  }}/>

source: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/location.md

In the component you are trying to reach you can then access the variable like this for example:

  componentDidMount: function() {
    var recievedMessage = this.props.location.state.message
  },

I hope this helps! :)

解决方案

tl;dr your best bet is to use a store like redux or mobx when managing state that needs to be accessible throughout your application. Those libraries allow your components to connect to/observe the state and be kept up to date of any state changes.

What is a <Route>?

The reason that you cannot pass props through <Route> components is that they are not real components in the sense that they do not render anything. Instead, they are used to build a route configuration object.

That means that this:

<Router history={browserHistory}>
  <Route path='/' component={App}>
    <Route path='foo' component={Foo} />
  </Route>
</Router>

is equivalent to this:

<Router history={browserHistory} routes={{
  path: '/',
  component: App,
  childRoutes: [
    {
      path: 'foo',
      component: Foo
    }
  ]
}} />

The routes are only evaluated on the initial mount, which is why you cannot pass new props to them.

Static Props

If you have some static props that you want to pass to your store, you can create your own higher order component that will inject them into the store. Unfortunately, this only works for static props because, as stated above, the <Route>s are only evaluated once.

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

Using location.state

location.state is a convenient way to pass state between components when you are navigating. It has one major downside, however, which is that the state only exists when navigating within your application. If a user follows a link to your website, there will be no state attached to the location.

Using A Store

So how do you pass data to your route's components? A common way is to use a store like redux or mobx. With redux, you can connect your component to the store using a higher order component. Then, when your route's component (which is really the HOC with your route component as its child) renders, it can grab up to date information from the store.

const Foo = (props) => (
  <div>{props.username}</div>
)

function mapStateToProps(state) {
  return {
    value: state.username
  };
}

export default connect(mapStateToProps)(Foo)

I am not particularly familiar with mobx, but from my understanding it can be even easier to setup. Using redux, mobx, or one of the other state management is a great way to pass state throughout your application.

Note: You can stop reading here. Below are plausible examples for passing state, but you should probably just use a store library.

Without A Store

What if you don't want to use a store? Are you out of luck? No, but you have to use an experimental feature of React: the context. In order to use the context, one of your parent components has to explicitly define a getChildContext method as well as a childContextTypes object. Any child component that wants to access these values through the context would then need to define a contextTypes object (similar to 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
}

You could even write your own higher order component that automatically injects the context values as props of your <Route> components. This would be something of a "poor man's store". You could get it to work, but most likely less efficiently and with more bugs than using one of the aforementioned store libraries.

What about React.cloneElement?

There is another way to provide props to a <Route>'s component, but it only works one level at a time. Essentially, when React Router is rendering components based on the current route, it creates an element for the most deeply nested matched <Route> first. It then passes that element as the children prop when creating an element for the next most deeply nested <Route>. That means that in the render method of the second component, you can use React.cloneElement to clone the existing children element and add additional props to it.

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

This is of course tedious, especially if you were to need to pass this information through multiple levels of <Route> components. You would also need to manage your state within your base <Route> component (i.e. <Route path='/' component={Base}>) because you wouldn't have a way to inject the state from parent components of the <Router>.

这篇关于如何通过 React_router 传递状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆