使用组件页面上的URL来识别并通过React Router从父级传递状态数据?

时间:2017-10-11 13:37:45

标签: react-router-v4

我正在使用React Router。在我的州,我有一些可通过身份识别识别的电视节目。在节目页面上,我需要加载特定节目的数据,将节目ID与URL的末尾相匹配。

我的州看起来像这样,但有更多的节目:

shows: [
  {
    id: 1318913
    name: "Countdown"
    time: "14:10"
  },
  {
    id: 1318914
    name: "The News"
    time: "15:00"
  }
]

在App.js中:

<BrowserRouter>
  <Switch>
    <Route
      exact
      path="/"
      render={() => {
        return <Table shows={this.state.shows} />;
      }}
    />
    <Route
      path="/show/:showID"
      render={() => {
        return <Show />;
      }}
    />
    <Route component={FourOhFour} />
  </Switch>
</BrowserRouter>;

React Router在显示页面上显示URL的showID部分。所以我可以将我的整个show状态传递给Show组件,然后从url中找到正确的show。但是我想这个效率低下?

我想知道我是否应该通过App.js中的ID查看节目,并且只将正确的节目传递给Show组件。这是更好的做法/更有效吗?

这是我的表组件:

class Table extends Component {
  render(props) {
    return (
      <table className="table table-striped table-bordered table-hover">
        <tbody>
        {
          this.props.shows.map((item)=>{
            return <TableRow
              name={item.name}
              time={item.time}
              key={item.eppisodeId}
              eppisodeId={item.eppisodeId}
              img={item.img}
            />
          })
        }
        </tbody>
      </table>
    )
  }
}

这是我的TableRow组件:

class TableRow extends Component {
  render(props) {
    const image = this.props.img !== null ?
      <img src={this.props.img} alt={this.props.name} />
      : null;
    const showUrl = '/show/' + this.props.eppisodeId;
    return (
      <tr className="tableRow">
        <td className="tableRow--imgTd">{image}</td>
        <td><Link to={showUrl}>{this.props.name}</Link></td>
        <td className="tableRow--timeTd">{this.props.time}</td>
      </tr>
    )
  }
}

2 个答案:

答案 0 :(得分:2)

正如我在您的问题中所看到的,您正在使用Link进行导航。考虑到您还希望通过链接发送数据,您可以将对象传递给它而不是React-router docs中提到的string path,因此您可以使用{{1}传递节目信息在state object组件中

TableRow

现在,您可以在const {name, time, episodeId, img} = this.props; <Link to={{pathname:showUrl, state: {show: {name, time, episodeId, img }}}}>{this.props.name}</Link> 组件中检索此信息

Show

您需要注意的另一件事是,您需要将道具传递给渲染函数

this.props.location.state && this.props.location.state.name

现在上述解决方案仅在您从App中导航时才有效,但是如果您更改URL将无效,如果您想使其更加健壮,您需要将数据传递给show组件然后优化生命周期功能

你愿意。这样做

 <Switch>
       <Route
      exact
      path="/"
      render={(props) => {
        return <Table shows={this.state.shows} {...props}/>;
      }}
    />
    <Route
      path="/show/:showID"
      render={(props) => {
        return <Show {...props}/>;
      }}
    />
    <Route component={FourOhFour} />
  </Switch>

然后在Show组件

<Switch>
       <Route
      exact
      path="/"
      render={(props) => {
        return <Table shows={this.state.shows} {...props}/>;
      }}
    />
    <Route
      path="/show/:showID"
      render={(props) => {
        return <Show shows={this.state.shows} {...props}/>;
      }}
    />
    <Route component={FourOhFour} />
</Switch>

然而,这就是像reduxreselect这样的图书馆有用的地方。使用Redux,您的数据class Show extends React.Component { componentDidMount() { const {shows, match} = this.props; const {params} = match; // get the data from shows which matches params.id here using `find` or `filter` or whatever you feel appropriate } componentWillReceiveProps(nextProps) { const {match} = this.props; const {shows: nextShows, match: nextMatch} = nextProps; const {params} = match; const {params: nextParams} = nextMatch; if( nextParams.showId !== params.showId) { // get the data from nextProps.showId and nextShows here } } } 将位于一个公共存储中,您可以在任何组件中访问它,shows为您提供了一个选项,可以创建一个备忘的选择器以获取相应的reselect数据来自show,因此不再重复相同的计算。请探讨这些并检查它们是否适合您的项目。

答案 1 :(得分:0)

组件参数可以接受一个功能。如果您使用props.match.params.id传递道具,则可以从网址中找到ID。当我们处于一个函数中时,我们能够从我们的状态中找到该节目并将其传递给Show组件。

<BrowserRouter>
  <Switch>
    <Route
      exact
      path="/"
      render={() => {
        return <Table shows={this.state.shows} />;
      }}
    />

    <Route path="/show/:id" component={(props)=>{
      const foundShow = this.state.shows.find((show)=>{
      const urlId = props.match.params.id;
         return show.eppisodeId === parseInt(urlId);
       });
       // {...props} is optional, it will pass the other properties from React Router
       return <Show show={foundShow} {...props} />
     }} />

    <Route component={FourOhFour} />
  </Switch>
</BrowserRouter>;

然而,有一些奇怪的行为。如果我在Show组件中console.log(this.props);,那么我可以看到它被渲染两次。第一次this.props.show为空,第二次有我传递的数据。这是一个真正的痛苦,因为我必须在渲染之前检查每个变量的存在,这使得我必须做错事......

更新:以下解决了上述问题,但我不知道这是不是一个好习惯:

class Show extends Component {
  render(props) {
    if (this.props.foundShow) {
      const {name, network, time} = this.props.foundShow;
      return (
        <div>
          <h2>
            {name} on {network} at {time}
          </h2>
        </div>
      )
    } else {
      return (
        <h2>Loading....</h2>
      )
    }
  }
}