如何通过 React_router 传递状态?

IT技术 reactjs react-router browser-history
2021-04-14 03:12:07

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

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.relativesthis.state.userName通过路线传递到我的“提要”组件中。但我收到此错误消息:

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

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

请帮忙!谢谢


解决方案:

下面的答案很有帮助,我感谢 ahors,但它们并不是最简单的方法。在我的情况下,最好的方法是这样的:当你改变路线时,你只需像这样附加一条消息:

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

我希望这有帮助!:)

5个回答

tl;dr你最好的选择是使用 store 之类的,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
    }
  ]
}} />

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

静态props

如果您有一些想要传递给商店的静态props,您可以创建自己的高阶组件,将它们注入商店。不幸的是,这只适用于静态props,因为如上所述,<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一种常见的方法是使用类似reduxor的存储mobx使用redux,您可以connect使用高阶组件将组件发送到商店。然后,当您的路线component(实际上是将您的路线组件作为其子项的 HOC)呈现时,它可以从商店中获取最新信息。

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

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

export default connect(mapStateToProps)(Foo)

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

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

没有商店

如果您不想使用商店怎么办?你倒霉了吗?不,但是你必须使用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> components 的props注入这将是一个“穷人的商店”。你可以让它工作,但很可能比使用上述商店库之一效率低下并且错误更多。

怎么样React.cloneElement

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

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> components传递此信息您还需要在您的基本<Route>组件(即<Route path='/' component={Base}>)中管理您的状态,因为您没有办法从<Router>.

@YannicHamann location.state 来自浏览器(history.pushState/replaceState 的第一个参数是与位置关联的可序列化状态),并带有警告,例如当您直接导航到页面时它为空。我发现 location.state 最适合临时数据,例如登录后导航到的 URL,“真实”状态最好保留在其他地方。
2021-05-25 03:12:07
问题是改变路线本身的状态
2021-05-30 03:12:07
请注意,React.PropTypes自 React v15.5 以来已移入不同的包中。请改用“prop-types”库:npmjs.com/package/prop-types
2021-06-07 03:12:07
那么为什么 LocationDescriptorObject 接口中有一个 .state 属性呢?这令人困惑 - 我在文档中找不到任何内容......我的意思是我无论如何都在使用 redux 但它的意图是什么?
2021-06-16 03:12:07

我知道回答这个问题可能为时已晚,但是对于将来对此感到疑惑的任何人,您可以这样做:

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 组件中访问配置props。这是一个关于这个问题的小步,但首先它是一个很好的接触!:)

一旦路由器组件被挂载,你就不能改变 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>)
}
我认为这并没有真正回答原始问题。这如何提供将路由绑定到状态的能力?
2021-05-28 03:12:07

对于像我这样的人,

你也可以正常渲染这个:

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>

这对我有用!

请注意,如果您使用的是 a query string,则需要添加search.

例如:

{
  key: 'ac3df4', // not with HashHistory!
  pathname: '/somewhere',
  search: '?some=search-string',
  hash: '#howdy',
  state: {
    [userDefined]: true
  }
}

花了大约 20 分钟才弄清楚为什么我的路线没有被渲染 😅