【问题标题】:How to render a component on button click in React?如何在 React 中单击按钮时呈现组件?
【发布时间】:2018-03-28 06:21:36
【问题描述】:

我正在为一个项目使用 React 和 Material UI,并且我正在实施付款方式。我基本上会支持不同类型的支付方式,根据用户选择的不同,我要显示一个表单,一旦用户填写表单并提交,我想返回到我之前的视图。我有一个看起来像这样的组件:

import React, { Component } from 'react';
import { List, ListItem } from 'material-ui';
import { Button } from '../../components';
import StripeForm from './stripe/form';
import PropTypes from 'prop-types';

class MyComp extends Component {
    constructor(props) {
        super(props);

        this.state = {
             paymentProviders: [],
             indexOfClickedItem: -1,
        };

        this.onListItemClicked = this.onListItemClicked.bind(this);
        this.onPayment = this.onPayment.bind(this);
    }

    onListItemClicked(paymentProvider, index) {
        let paymentProviders = {
            providerName: paymentProvider.ProviderName,
            publicKey: paymentProvider.PublicKey,
        };
        this.setState({
            paymentProviders: paymentProviders,
            indexOfClickedItem: index,
        });
    }

    onPayment() {
        switch (this.state.paymentProviders.providerName) {
             case "stripe":
                 // render the form for stripe payment
                 return ( <StripeForm /> );

             case "paypal":
                 // render the form for paypal payment

             default:
                 return null;
         }
    }

    render() {
        return (
            <div>
                <div>
                    <List>
                        {this.props.paymentProviders.map((pp, index) => {
                            return (
                                <ListItem key={pp.ProviderName}
                                        primaryText={pp.ProviderName}
                                        onClick={() => this.onListItemClicked(pp, index)}
                                />
                            )
                        })}
                    </List>
                </div>

                <div>
                    <Button onClick={this.onPayment}
                            label="Pay" />
                </div>
            </div>
        );
    }
}

MyComp.propTypes = {
    paymentProviders: PropTypes.array.isRequired,
};

export default MyComp;

因此,基本上,根据单击哪个 ListItem,我会更新状态中的 indexOfClickedItem,然后还会更新有关支付提供商的一些详细信息。但是,我主要想要实现的是,当我的按钮被点击时,取决于选择了哪个支付提供商(意味着之前点击/选择了哪个列表),我想渲染另一个组件。任何想法如何实现它?

【问题讨论】:

  • 你可以使用React Router,尤其是Switch
  • 所以你有选择,你也可以使用内联条件渲染来根据组件的状态隐藏和显示你的组件。
  • @fungusanthrax 代码示例非常受欢迎。
  • render() =&gt; { var show = this.state.modalIsOpen; return ( {show === true &amp;&amp; &lt;Modal /&gt; } {show === false &amp;&amp; &lt;Modal2 /&gt; } ) } 参考这里:reactjs.org/docs/conditional-rendering.html
  • @fungusanthrax 是的,我知道条件渲染的想法,但我不完全了解如何将其应用于我的场景,因为我需要仅在按钮单击时渲染新组件。

标签: reactjs


【解决方案1】:

只需在您的渲染方法中添加一个条件,它会检查状态并在条件正确时渲染新组件:

render() {
    // render payment provider component for selected provider
    const {paymentProviders, indexOfClickedItem, paymentClicked} = this.state;
    const selectedPP = paymentProviders && paymentProviders[indexOfClickedItem];
    if (paymentClicked) {
        // whatever mechanism you want to use to decide
        // what to render for this payment provider...
        const ComponentToRender = selectedPP.Component;
        return (
          <ComponentToRender
            // unselects the item when the user finishes the payment
            onComplete={() => this.setState({indexOfClickedItem: -1})}
            prop1={"foo"}
          />
        );
    }

    // if nothing selected, render list
    return (
        <div>
            <div>
                <List>
                    {this.props.paymentProviders.map((pp, index) => {
                        return (
                            <ListItem key={pp.ProviderName}
                                    primaryText={pp.ProviderName}
                                    onClick={() => this.onListItemClicked(pp, index)}
                            />
                        )
                    })}
                </List>
            </div>

            <div>
                <Button onClick={this.onPayment}
                        label="Pay" />
            </div>
        </div>
    );
}

您的onPayment 函数应该发出this.setState({paymentClicked: true}) 来触发新的渲染路径。

【讨论】:

  • 这和我想要的有点不同。在您的代码中,每当用户单击其中一个 ListItems 时,您基本上都会呈现一个新组件。但我想要做的是,每当用户单击“支付”按钮时,我想呈现一个新组件。为简洁起见,我删除了样式,但是在我的代码中发生的情况是,当用户单击其中一个 ListItem 时,单击的 ListItem 会更改样式,因此用户知道他/她单击了哪个,另外我更新了indexOfClickedItem。然后,当用户按下支付按钮时,我就想渲染新组件。
  • 是同一个概念。
  • @nbkhope 然后,我看不出它是如何相同的。您能否更新代码以反映更改?
  • 我添加了几行代码来向您展示如何从onPayment 触发它。想法其实是一样的:当用户触发某个事件时,你调用setState 设置一些数据,然后你的render 方法检查该数据并呈现不同的东西。
【解决方案2】:

您可以使用条件渲染。

首先在构造函数内部初始化一个变量来存储表单,并添加一个状态viewForm来管理是否查看表单:

constructor(props) {
    super(props);

    this.state = {
         paymentProviders: [],
         indexOfClickedItem: -1,
         viewForm: false
    };

    this.onListItemClicked = this.onListItemClicked.bind(this);
    this.onPayment = this.onPayment.bind(this);
    this.paymentForm = null;  //this
}

点击按钮时,选择支付模式时有条件地为其赋值,并更改状态以查看表单:

    switch (this.state.paymentProviders.providerName) {
         case "stripe":
             this.paymentForm = <StripeForm/>
             break;
         case "paypal":
             this.paymentForm = <PaypalForm/>
             break;
         default:
              this.paymentForm = null;
     }
     this.setState({ viewForm: true });

.. 然后有条件地渲染它:

<div className='form-container'>
  {(this.state.viewForm) ?
  this.paymentForm : ''}
</div>

【讨论】:

  • 您不需要this 上的那个变量。您可以将动态组件存储在局部变量中。 let component; if (this.state.paymentProviders.providerName === 'stripe') { component = &lt;StripeForm /&gt; } else if (...) { ... } .... &lt;div&gt;{component}&lt;/div&gt;
  • 是的,但是如何确保新视图仅在单击按钮时呈现,而不是在单击 ListItem 时呈现?
  • @typos 如何使用组件状态(布尔)属性来跟踪您是否点击了它?
猜你喜欢
  • 1970-01-01
  • 2020-12-29
  • 1970-01-01
  • 2018-05-29
  • 2017-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多