不使用render。)方法中的React.cloneElement传递道具

时间:2020-10-31 12:45:05

标签: javascript reactjs react-props react-component

我有两个React组件,一个Layout类和一个HomePage类:

HomePage是需要具有products道具的组件。

HomePage.js

import React, { Component } from 'react';

export class HomePage extends Component {
    render() {
        if (!this.props.products) {
            return (<div>Products not loaded yet</div>);
        }
        return (<div>Products loaded!</div>);
    }
}

Layout是一个组件,用于显示来自使用react-router建立的路由的子级。 此类课程负责将products道具传递给使用React.cloneElement的孩子

Layout.js

import React, { Component } from 'react';
import { NavMenu } from './NavMenu';
import { Footer } from './Footer';

export class Layout extends Component {    
    constructor(props) {
      super(props);
      this.state = {
          products: null,
          loading: true
      };
    }    

    // Make an api call when the component is mounted in order to pass
    // additional props to the children
    componentDidMount() {
      this.populateProductsData();
    }

    async populateProductsData() {
      const response = await fetch('api/products/all');
      const data = await response.json();
      this.setState({ products: data, loading: false });    
    }

    render() {
        if (this.state.loading) {
            return (<div>App loading</div>);
        }

        const childrenWithProps = React.Children.map(this.props.children, child => {
            const props = { products: this.state.products };
            if (React.isValidElement(child)) {
                return React.cloneElement(child, props);
            }
            return child;
        });

        return (
          <div>
                <NavMenu />
                {childrenWithProps}
                <Footer />
          </div>
        );
    }
}

App组件中进行路由:

App.js

export default class App extends Component {
  render () {
    return (
        <Layout>
            <Route exact path='/'
                component={HomePage}/>
        </Layout>
    );
  }

因此,我希望

  1. 在尚未进行API调用的情况下,在页面上显示App loading消息
  2. 在道具未传递给Products not loaded yet子级的情况下,在页面上显示Layout消息
  3. 在页面上显示Products loaded!消息

但是,应用程序停留在第二步:products道具永远不会被子组件接收。代码可以编译,没有运行时错误,并且后端Api被触发并发送有效响应。

为什么product道具在子render()子组件的HomePage方法中永远不可用?


编辑:

按照@Nikita Chayka的回答,道具应在路线传递:

Layout.js

export class Layout extends Component {    
    render() {
        return (
          <div>
                <NavMenu />
                {this.props.children}
                <Footer />
          </div>
        );
  }
}

App.js

export default class App extends Component {
    constructor(props) {
        super(props);

        this.state = {
            products: null,
            loading: true
        };
    }    

    componentDidMount() {
        this.populateProductsData();
    }

    async populateProductsData() {
        const response = await fetch('/api/products/all');
        const data = await response.json();
        this.setState({ products: data, loading: false });    
    }

    render() {
        if (this.state.loading)
            return (<div>App loading</div>);

        return (
        <Layout>
            <Route exact path='/'
                render={(props) => (<HomePage {...props} products={this.state.products}/>)}/>
        </Layout>
    );
  }
}

1 个答案:

答案 0 :(得分:0)

您的Layout组件会将产品prop传递给Route组件,而不是Home组件,基本上您将拥有

<Route products={} component={Home} path="/" exact/>

但是您需要将其传递给首页,您可以在此处查看想法-https://ui.dev/react-router-v4-pass-props-to-components/

编辑

您不应仅向渲染提供组件属性给路由。