简体   繁体   English

在 render() 方法中没有通过 React.cloneElement 传递道具

[英]Props are not passed with React.cloneElement in the render() method

I have two react components, a Layout class and a HomePage class:我有两个反应组件,一个Layout类和一个HomePage类:

HomePage is a component which needs to have a products prop. HomePage是一个需要有products道具的组件。

HomePage.js主页.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 is a component that displays children coming from routes established with react-router . Layout是一个组件,用于显示来自react-router建立react-router This class is in charge to pass the products prop to children using React.cloneElement这个类负责使用React.cloneElementproducts道具传递给孩子

Layout.js布局.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>
        );
    }
}

The routing is made in an App component:路由是在App组件中进行的:

App.js应用程序.js

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

Hence, I am expecting to因此,我期待

  1. Have a page with the App loading message while the API call hasn't been made在未进行 API 调用时有一个包含App loading消息的页面
  2. Have a page with the Products not loaded yet message while the prop hasn't been passed to the Layout children当道具尚未传递给Layout子项时,有一个包含Products not loaded yetProducts not loaded yet消息的Layout
  3. Have a page with the Products loaded!有一个Products loaded!Products loaded!的页面Products loaded! message信息

However, the application is stuck at step two: the products prop is never received by the children components.但是,应用程序停留在第二步:子组件永远不会收到products属性。 The code compiles, there are no runtime errors, and the back-end Api is triggered and sends a valid response.代码编译通过,没有运行时错误,后端 Api 被触发并发送有效响应。

Why the product props will never be available in the render() method of the child HomePage component?为什么product道具永远不会在子HomePage组件的render()方法中可用?


EDIT:编辑:

Following @Nikita Chayka's answer, the props should be passed at routing:按照@Nikita Chayka 的回答,应该在路由时传递道具:

Layout.js布局.js

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

App.js应用程序.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>
    );
  }
}

Your Layout component will pass products prop to Route component, not Home component, basically you will have您的 Layout 组件会将 products 属性传递给 Route 组件,而不是 Home 组件,基本上您将拥有

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

But you need to pass it down to Home, you could check for ideas here - https://ui.dev/react-router-v4-pass-props-to-components/但是你需要把它传递给 Home,你可以在这里检查想法 - https://ui.dev/react-router-v4-pass-props-to-components/

EDIT编辑

You should not provide component property to Route, only render.您不应向 Route 提供组件属性,而应仅提供渲染。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM