【问题标题】:How to pass React Component prop to child function using {children}?如何使用 {children} 将 React Component 道具传递给子函数?
【发布时间】:2020-07-17 20:02:54
【问题描述】:

我是 React 新手,所以这可能很明显,但我不能通过 prop 传递给从其父级创建组件的函数。

我可以将 props 传递给子组件,但同样不适用于函数。

我有<Subscription>,我可以像这样从它的父post传递参数:

<Subscription auth={auth} stripeAmount={post.amount} stripePlanId={post.planid}/>

这将创建一个 Stripe 订阅。我想将订阅限制为订阅stripePlanId,我通过以下方式订阅:

class Subscription extends React.Component {

  // https://stripe.com/docs/checkout#integration-custom
  componentDidMount() {
    this.stripeCheckout = window.StripeCheckout.configure({
      ...etc...
      email: this.props.auth.email,
    })
  }

  newSubscription = () => {
    var stripePlanId = this.props.stripePlanId;
    this.stripeCheckout.open({
      amount: this.props.stripeAmount, // in cents
      description: this.props.stripePlanId,
      token: function(token){
        createSubscription(token, stripePlanId)
      }
    })
  }

 ..etc..

这很好用。但是现在要通过 stripePlanId 我不知道如何通过 stripePlanId 因为它是通过函数呈现的 - 这个 {children} 参数似乎只在函数中传递,并且尝试添加参数会导致错误,他们不是它期望对传递的参数起作用的函数:

const FireflySubscription = ({children}) => (
  <FirebaseAuth>
    { ({isLoading, error, auth}) => {
      if (error || isLoading || !auth) {
        //it pushes these arguments to the parent function
        return children({ 
          error,
          isLoading,
          subscription: null,
        })
      }

      // the issue - how to populate this?
      const stripePlanId = ""  

      // when working this should return the subscription for only this planId
      if (stripePlanId) {
        return <FirestoreCollection
        path="subscriptions"
        filter={[['createdBy', '==', auth.uid], ['stripePlanId','==', stripePlanId]]}
      >
        { ({error, isLoading, data}) => {
          return children({
            error,
            isLoading,
            subscription: data.length > 0 ? data : null,
          })
        }}
      </FirestoreCollection>

      }

      return <FirestoreCollection
        path="subscriptions"
        filter={['createdBy', '==', auth.uid]}
      >
        { ({error, isLoading, data}) => {
          return children({
            error,
            isLoading,
            subscription: data.length > 0 ? data : null,
          })
        }}
      </FirestoreCollection>

    }}
  </FirebaseAuth>
)

export default FireflySubscription

我试过用另一种方法通过,但是“作用域”没有通过:

getPostSubscriptions = stripePlanId => {
    return <FireflySubscription>
// it gets these arguments from FireflySubscription function above
    { ({error, isLoading, subscription}) => { 
      if (error) {
        return <Error error={error} />
      }

      if (isLoading) {
        return <p>loading...</p>
      }

      if (!subscription) {
        return <div>
          <p><strong>Subscribe to get paid features</strong></p>
          ..etc...
        </div>
      }

      ..etc...

    }}
  </FireflySubscription>
  }

  render() {
    return this.getPostSubscriptions(this.props.stripePlanId)
  }
}

非常感谢任何线索!我正在改编的原始代码来自https://github.com/sampl/firefly,如果有帮助的话。

【问题讨论】:

标签: javascript reactjs components react-props


【解决方案1】:

通过您引用的存储库,您似乎正在从订阅组件中呈现FireflySubscription,例如

class Subscription extends React.Component {
    // other code here

    render() {
       return (
           <FireflySubscription>
               { ({error, isLoading, subscription}) => {
                   /*Some components here*/
               }}
           </FireflySubscription>
       )
    }
}

考虑到上述情况,最简单的解决方案是将stripePlanId 作为道具传递给FireflySubscription 组件,并在组件内与子组件一起接收它

现在stripePlanId 是在Subscription 组件内部计算的,它可以很容易地直接从父级传递给FireflySubscription 的子级,而不必担心它会通过 FireflySubscription 路由

所以解决方案看起来像

class Subscription extends React.Component {
    // other code here

    render() {
       return (
           <FireflySubscription stripePlanId={this.props.stripePlanId}>
               { ({error, isLoading, subscription}) => {
                   // stripePlanId can be passed on to any children here using this.props.stripePlanId directly
                   /*Some components here*/
               }}
           </FireflySubscription>
       )
    }
}

现在在 FireflySubscription 中,您将使用它作为

const FireflySubscription = ({children, stripePlanId}) => (
  <FirebaseAuth>
    { ({isLoading, error, auth}) => {
      if (error || isLoading || !auth) {
        //it pushes these arguments to the parent function
        return children({ 
          error,
          isLoading,
          subscription: null,
        })
      }

      if (stripePlanId) {
        return <FirestoreCollection
        path="subscriptions"
        filter={[['createdBy', '==', auth.uid], ['stripePlanId','==', stripePlanId]]}
      >
        { ({error, isLoading, data}) => {
          return children({
            error,
            isLoading,
            subscription: data.length > 0 ? data : null,
          })
        }}
      </FirestoreCollection>

      }

      return <FirestoreCollection
        path="subscriptions"
        filter={['createdBy', '==', auth.uid]}
      >
        { ({error, isLoading, data}) => {
          return children({
            error,
            isLoading,
            subscription: data.length > 0 ? data : null,
          })
        }}
      </FirestoreCollection>

    }}
  </FirebaseAuth>
)

【讨论】:

    【解决方案2】:

    使用Render Props

    术语“render prop”是指一种在 React 组件之间共享代码的技术,使用值为函数的 prop。

    带有 render prop 的组件接受一个返回 React 元素的函数并调用它,而不是实现自己的渲染逻辑。

    ParentPost 组件:

    const ParentPost = () => {
        <Subscription auth={auth} stripeAmount={post.amount} stripePlanId={post.planid}>
            {(stripePlanId) => <FireflySubscription stripePlanId={stripePlanId}/>}
        </Subscription>
    };
    

    订阅组件:在您的渲染方法中,将stripePlanId 作为道具传递给children

    class Subscription extends React.Component {
      // https://stripe.com/docs/checkout#integration-custom
      componentDidMount() {
        this.stripeCheckout = window.StripeCheckout.configure({
          // ...etc...
          email: this.props.auth.email
        });
      }
    
      newSubscription = () => {
        var stripePlanId = this.props.stripePlanId;
        this.stripeCheckout.open({
          amount: this.props.stripeAmount, // in cents
          description: this.props.stripePlanId,
          token: function(token) {
            createSubscription(token, stripePlanId);
          }
        });
      };
      
      render() {
          <div>
              ...
              {this.props.children(this.props.stripePlanId)}
              ...
          </div>
      }
    }
    

    FireflySubscription 组件:在这里,像这样从父级接收stripePlanId:。

    const FireflySubscription = ({children, stripePlanId}) => (
        <FirebaseAuth>
            {({isLoading, error, auth}) => {
                if (error || isLoading || !auth) {
                    //it pushes these arguments to the parent function
                    return children({
                        error,
                        isLoading,
                        subscription: null,
                    })
                }
    
                
                //const stripePlanId = stripePlanIdFromParent; // dont need this as we are destructuring from props
    
                // when working this should return the subscription for only this planId
                if (stripePlanId) {
                ...
    

    【讨论】:

      猜你喜欢
      • 2021-06-07
      • 1970-01-01
      • 2021-02-20
      • 1970-01-01
      • 1970-01-01
      • 2020-12-19
      • 2020-11-20
      • 2021-12-25
      • 2022-01-24
      相关资源
      最近更新 更多