【问题标题】:Props are not passed with React.cloneElement in the render() method在 render() 方法中没有使用 React.cloneElement 传递道具
【发布时间】:2020-10-31 12:45:05
【问题描述】:

我有两个 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 属性在子HomePage 组件的render() 方法中永远不可用?


编辑:

按照@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>
    );
  }
}

【问题讨论】:

    标签: javascript reactjs react-props react-component


    【解决方案1】:

    您的 Layout 组件会将 products 属性传递给 Route 组件,而不是 Home 组件,基本上您将拥有

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

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

    编辑

    你不应该向 Route 提供组件属性,只需要渲染。

    【讨论】:

    • 如果你使用渲染,你不应该使用组件属性
    猜你喜欢
    • 1970-01-01
    • 2021-05-05
    • 1970-01-01
    • 1970-01-01
    • 2019-10-15
    • 2020-01-09
    • 1970-01-01
    • 2019-04-07
    • 2019-11-22
    相关资源
    最近更新 更多