React-Router在主要组件和侧边栏组件之间传递道具

时间:2017-04-27 05:39:56

标签: javascript reactjs meteor react-router

我正在使用Meteor和React-Router,我有以下代码:

Routes.jsx:

Meteor.startup(() => {
  render(
    <Router history={browserHistory}>
      <Route path='/' component={App}>
        <IndexRoute components={{ main: SelectTable, sidebar: MenuBar }} />
        <Route path='/DisplayTable/:tableId'
          components={{ main: DisplayTable, sidebar: MenuBar }} />
      </Route>
      <Route path='*' component={NotFound} />
    </Router>,
    document.getElementById('react-root'));
});

App.jsx:

export class App extends Component {
  render() {
    // if there's only one child logic here, irrelevant
    return (
      <div className='container'>
        <div className="Main">
          {this.props.main}
        </div>
        <div className="Sidebar">
          {this.props.sidebar}
        </div>
      </div>);
  }
}

我的 DisplayTable 组件侦听对数据库的Meteor订阅,并最终获取这些属性:

DisplayTable.propTypes = {
  tableId: PropTypes.string.isRequired,
  loading: PropTypes.bool.isRequired,
  rows: PropTypes.array.isRequired,
  cols: PropTypes.array.isRequired,
  user: PropTypes.object,
};

我的 MenuBar 组件会显示:

<li><InsertRow tableId={this.props.params.tableId}/></li>

InsertRow 具有这些属性

InsertRow.propTypes = {
  rows: PropTypes.array,
  tableId: PropTypes.string,
};

其中InsertRowDisplayTable的行属性完全相同。

如何将属性从主要组件传递到侧边栏,以便我可以将其从那里传递给组件?

  • 也许有React.cloneElement的东西,虽然我真的无法绕过那个......
  • 我查看了mainsidebar的所有属性,似乎找不到任何有用的内容......

变通:

  • 理论上我可以订阅并获取数据,因为我有tableId,但这似乎过于愚蠢,因为这两个组件实际上是在同一个路径中呈现。
  • 我还可以在MenuBar上创建一个假div,并在我显示表时使用jQuery替换它,但这似乎没有反应。
  • 我还可以为应用的 DisplayTable 部分制作另一个菜单,但我正在努力避免混乱。

(我没有使用反应路由器4.0,如果它与答案相关,使用3.0.5,最新版本的流星,虽然我猜这在这种情况下不相关)

编辑:我想我会在路径上方添加容器,所以我已经有了数据。虽然我会留下这个以防万一有更好的建议,但有点有意义。

1 个答案:

答案 0 :(得分:1)

虽然可能有更好的方法,但我会在下面解释我最终做的事情:

<强> Routes.jsx

Meteor.startup(() => {
  render(
    <Router history={browserHistory}>
      <Route path='/' component={App}> 
        //... like before

        <Route path='/DisplayTable' component={ Comp } >
          <Route path='/DisplayTable/:tableId'
            components={{ main: DisplayTable, sidebar: MenuBar }} />
        </Route>

      </Route>
      <Route path='*' component={NotFound} />
    </Router>,
    document.getElementById('react-root'));
});

然后我添加了组件布局Comp

<强> Comp.jsx

class Comp extends Component {
  render() {
    // this is the final html for our table
    let displayTable = [];
    let menuBar = [];
    // while the data is loading, the html is a spinner
    if (this.props.loading) {
      displayTable.push(
        <div key='table-container' className='table-container table-container-no-data'>
          <div key='loading'>
            <span>Loading data...</span>
            <Spinner key='spinner' spinnerName='three-bounce' />
          </div>
        </div>);
    } else {
      // the Display Table properties
      displayTable = React.Children.map(this.props.main, child => React.cloneElement(child, {
        rows: this.props.rows,
        cols: this.props.cols,
      }));
      // the Menu Bar properties
      menuBar = React.Children.map(this.props.sidebar, child => React.cloneElement(child, {
        rows: this.props.rows,
        cols: this.props.cols,
      }));
    }

    return (
      <div className='container'>
        <div className="content">
          {displayTable}
        </div>
        <div className="menu">
          {menuBar}
        </div>
      </div>);
  }
}

Comp.propTypes = {
  loading: PropTypes.bool.isRequired,
  rows: PropTypes.array.isRequired,
  cols: PropTypes.array.isRequired,
  //... etc
};
/**
 * A Meteor createContainer component which retrieves data from Meteor & Mongo
 */
export default createContainer((props) => {
  // get the rows & cols by Meteor subscriptions here, as well as a loading to figure out when the subscription finished (this was originally in DisplayTable)
}

<强> DisplayTable.jsx

DisplayTable.propTypes = {
  rows: PropTypes.array,
  cols: PropTypes.array,
};

(事实证明这些是我需要的而不是上面的 - 在整个组件中使用它们,但基本上从Comp获取它们

<强> MenuBar.jsx

MenuBar.propTypes = {
  rows: PropTypes.array,
  cols: PropTypes.array,
};

(与上面相同,在调用InsertRow时使用它们)

MenuBar也会像InsertRow

那样调用<li><InsertRow tableId={this.props.params.tableId} cols={this.props.cols} isDisabled={false} /></li>