我如何通过React_router传递状态?

Jon*_*ner 53 browser-history reactjs react-router

这是导致我麻烦的文件:

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>
    );
  }
});
Run Code Online (Sandbox Code Playgroud)

我试图将新的this.state.relativesthis.state.userName通过路线传递到我的"feed"组件.但我收到此错误消息:

警告:[react-router]你无法改变; 它会被忽略

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

请帮忙!谢谢


解:

下面的答案很有帮助,我感谢他们,但他们并不是最简单的方法.在我的情况下做到这一点的最好方法是:当您更改路线时,您只需将消息附加到它,如下所示:

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

或者如果你通过链接这样做:

<Link 
    to={{ 
    pathname: '/pathname', 
    state: { message: 'hello, im a passed message!' } 
  }}/>
Run Code Online (Sandbox Code Playgroud)

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

在您尝试访问的组件中,您可以像这样访问变量,例如:

  componentDidMount: function() {
    var recievedMessage = this.props.location.state.message
  },
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助!:)

Pau*_*l S 30

文艺青年最爱的你最好的选择是使用像商店reduxmobx管理需要在整个应用程序中访问状态时.这些库允许您的组件连接/观察状态并保持最新的状态更改.

什么是<Route>

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

这意味着:

<Router history={browserHistory}>
  <Route path='/' component={App}>
    <Route path='foo' component={Foo} />
  </Route>
</Router>
Run Code Online (Sandbox Code Playgroud)

相当于:

<Router history={browserHistory} routes={{
  path: '/',
  component: App,
  childRoutes: [
    {
      path: 'foo',
      component: Foo
    }
  ]
}} />
Run Code Online (Sandbox Code Playgroud)

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

静态道具

如果您要将某些静态道具传递到商店,则可以创建自己的高阶组件,将其注入商店.不幸的是,这仅适用于静态道具,因为如上所述,<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>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

运用 location.state

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

使用商店

那么如何将数据传递给路线component?一种常见的方式是使用像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)
Run Code Online (Sandbox Code Playgroud)

我并不是特别熟悉mobx,但根据我的理解,它可以更容易设置.使用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
}
Run Code Online (Sandbox Code Playgroud)

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

怎么样React.cloneElement

还有另一种方式,提供道具到<Route>component,但它一次只能工作一个级别.实质上,当React Router基于当前路由渲染组件时,它会为最深层嵌套的匹配创建一个元素<Route>.然后,children在为下一个最深层嵌套的元素创建元素时,它将该元素作为prop 传递<Route>.这意味着在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>
)
Run Code Online (Sandbox Code Playgroud)

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

  • 这在 2022 年已经相当过时了。它也是固执己见和误导性的。单独使用全局存储与通过导航传递状态具有相同的问题,并且作者没有表明状态需要“在整个应用程序中可访问”。他们只需要在导航时经过该州,这不适合全球商店。 (2认同)

Kha*_*zam 0

一旦挂载了路由器组件,就无法更改 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>)
}
Run Code Online (Sandbox Code Playgroud)