我如何才能通过this.props.children将道具从父母传递给孩子?

时间:2018-09-27 12:42:00

标签: javascript reactjs react-router

我很难将道具传递给this.props.children

我有一个组件MainLayout,我想将道具传递给this.props.children,但他的孩子们像这样:

AppRouter.js

export default class AppRouter extends Component {

  render() {

    return (
      <HashRouter>
        <Switch>
          <MainLayout>
            <Route exact path="/" component={PubsList} />
            <Route exact path="/add-pub" component={AddPub} />
            <Route exact path="/add-pub/:id" component={AddPub} />
          </MainLayout>
        </Switch>
      </HashRouter>
    )
  }
}

MainLayout.js:我使用React.Children和React.CloneElement传递道具

export default class MainLayout extends Component {

 constructor(props) {
  super(props);
  this.state = {
   foo: "foo"
  };

  render() {

    return (
      <div className="container" >
        <Menu inverted color='teal' fixed="top" style={{ margin: "0", padding: "20px", borderRadius: "0", display: "block" }}>    
          <Link to="/">
            <Header as='h2' content='PandaBar' floated="left" style={{ color: "white", margin: "0" }} />
          </Link>    
        </Menu>    

        <div className="content" style={{ marginTop: "70px", overflow: "hidden" }} >    

          {React.Children.map(this.props.children, child => {
           return React.cloneElement(child, { foo: this.state.foo })
          })}    

        </div>
      </div>
    );
  }
}

但是,一旦我的路线获得了道具,它就会像这样:

<HashRouter>
   <Switch>
     <MainLayout>
        <Route exact path="/" component={PubsList} foo="foo"/>
        <Route exact path="/add-pub" component={AddPub} foo="foo"/>
        <Route exact path="/add-pub/:id" component={AddPub} foo="foo"/>
     </MainLayout>
    </Switch>
</HashRouter>

那么,如何通过这种配置将props foo传递给组件PubsList和AddPub?

2 个答案:

答案 0 :(得分:1)

Route通过使用render道具而不是component道具,确实提供了一种将自定义道具传递到组件的方法。您将一个函数传递给render道具,该函数将使用与通常使用component时自动传递的道具相同的道具来调用。然后,您可以使用这些道具做任何想做的事

此示例(不包括mainLayout组件)如下所示:

<Route render={(routeProps) => (
  <PubsList hello="world" {...routeProps} />
)}/>

因此,使用此命令,您可以在组件上放置任意道具。但是然后如何让MainLayout指示那些额外的道具是什么?我认为您需要修改MainLayout才能拥有自己的渲染道具。

render() {
  let children = null;
  if (this.props.render) {
    children = this.props.render({ foo: this.state.foo })
  }

  return (
    <div className="container" >
      <Menu inverted color='teal' fixed="top" style={{ margin: "0", padding: "20px", borderRadius: "0", display: "block" }}>    
        <Link to="/">
          <Header as='h2' content='PandaBar' floated="left" style={{ color: "white", margin: "0" }} />
        </Link>    
      </Menu>    

      <div className="content" style={{ marginTop: "70px", overflow: "hidden" }} >    
        {children}
      </div>
    </div>
  );
}

您将像这样使用它:

<MainLayout render={(layoutProps) => (
  <React.Fragment>
    <Route exact path="/" render={(routeProps) => 
      <PubsList {...layoutProps} {...routeProps} />
    }/>
    <Route exact path="/add-pub" render={(routeProps) => 
      <AddPub {...layoutProps} {...routeProps} />
    }/>
    <Route exact path="/add-pub/:id" render={(routeProps) => 
      <AddPub {...layoutProps} {...routeProps} />
    }/>
  </React.Fragment>
)} />

答案 1 :(得分:1)

在示例foo中,prop被传递到错误的组件(Route)。

要传递给路线组件,应改为更改路线component道具:

const withFoo = (Comp, foo) => props => <Comp {...props} foo={foo}/>;
...

  render() {

    return (
      ...
      {React.Children.map(this.props.children, route => {
        return React.cloneElement(route, {
          component: withFoo(route.props.component, this.state.foo)
        });
      })}    
      ...
    );
  }

虽然使用Route渲染道具作为另一个答案可能更直接。