调用高阶组件时,在 React 类之外访问 prop [英] Access prop outside of class in React when calling Higher Order Component

查看:27
本文介绍了调用高阶组件时,在 React 类之外访问 prop的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用高阶组件 (HOC) 模式来重用一些连接到状态并使用 Redux Form formValueSelector 方法的代码.

I am trying to use a Higher Order Component(HOC) pattern to reuse some code that connects to state and uses the Redux Form formValueSelector method.

formValueSelector 需要一个引用表单名称的字符串.我想动态设置它,并且能够在需要项目值时使用此 HOC.我使用项目值进行计算.

formValueSelector requires a sting referencing the name of the form. I would like to set this dynamically and be able to use this HOC whenever I need the values of items. I use the item values to make calculations.

在下面的代码中,向 HOC 传递了组件和一个字符串.我想将此设置为从父级(表单)传入的道具 formName.

In the code below the HOC is passed the component and a string. I would like to set this to the prop formName that has been passed in from the parent(form).

我是 HOC 模式的新手,因此非常感谢任何提示.

I am new to the HOC pattern so any tips would be most appreciated.

HOC

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { formValueSelector } from 'redux-form';

function FormItemsValueSelectorHOC(FormElement, formName) {
  const selector = formValueSelector(formName);
  @connect(state => {
    console.log(state);
    const items = selector(state, 'items');
    return {
      items
    };
  }, null)
  class Base extends Component {
    render() {
      return (
        <FormElement {...this.props} />
      );
    }
  }
  return Base;
}
export default FormItemsValueSelectorHOC;

包裹组件

import React, { Component, PropTypes } from 'react';
import { Field } from 'redux-form';
import formItemsValueSelectorHOC from '../Utilities/FormItemsValueSelectorHOC';

const renderField = ({ placeholder, input, type}) => {
  return (
    <input
      {...input}
      placeholder={placeholder}
      type={type}
    />
  );
};

class StatementLineItemDesktop extends Component {
  static propTypes = {
    items: PropTypes.array.isRequired,
    index: PropTypes.number.isRequired,
    item: PropTypes.string.isRequired,
    fields: PropTypes.object.isRequired,
    formName: PropTypes.string.isRequired
  };

  calculateLineTotal(items, index) {
    let unitPrice = '0';
    let quantity = '0';
    let lineTotal = '0.00';
    if (items) {
      if (items[index].price) {
        unitPrice = items[index].price.amountInCents;
      }
      quantity = items[index].quantity;
    }
    if (unitPrice && quantity) {
      lineTotal = unitPrice * quantity;
      lineTotal = Number(Math.round(lineTotal+'e2')+'e-2').toFixed(2); 
    }
    return <input value={lineTotal} readOnly placeholder="0.00" />;
  }

  render() {
    const { items, index, item, fields, formName} = this.props;
    return (
      <tr id={`item-row-${index}`} key={index} className="desktop-only">
        <td>
          <Field
            name={`${item}.text`}
            type="text"
            component={renderField}
            placeholder="Description"
          />
        </td>
        <td>
          <Field
            name={`${item}.quantity`}
            type="text"
            component={renderField}
            placeholder="0.00"
          />
        </td>
        <td>
          <Field
            name={`${item}.price.amountInCents`}
            type="text"
            component={renderField}
            placeholder="0.00"
          />
        </td>
        <td className="last-col">
          <Field
            name={`${item}.price.taxInclusive`}
            type="hidden"
            component="input"
          />
          {::this.calculateLineTotal(items, index)}
          <a
            className="remove-icon"
            onClick={() => fields.remove(index)}
          >
            <span className="icon icon-bridge_close" />
          </a>
        </td>
      </tr>
    );
  }
}

export default formItemsValueSelectorHOC(StatementLineItemDesktop, 'editQuote');

推荐答案

TLDR:使用 ownProps 参数

TLDR: use ownProps parameter

你应该做的草稿

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { formValueSelector } from 'redux-form';

function FormItemsValueSelectorHOC(FormElement) {
  @connect((state, ownProps) => {
    const formName = ownProps.formName;
    const selector = formValueSelector(formName);
    const items = selector(state, 'items');
    return {
      items
    };
  }, null)
  class Base extends Component {
    render() {
      // Now in here you should omit `formName` from the props you are
      // passing to your Form Element since it's not used overthere
      return (
        <FormElement {...this.props} />
      );
    }
  }
  return Base;
}
export default FormItemsValueSelectorHOC;

这将是您创建连接组件的方式

And this will be the way you will create your connected component

formItemsValueSelectorHOC(StatementLineItemDesktop);

这就是你使用它的方式

<ConnectedStatementLineItemDesktop formName={"editQuote"} />

让我解释一下这是如何工作的

Let me explain a bit more how this work

你缺少的是 React-Redux API,你可能应该更多地探索它,因为它已经考虑了很多这样的用例

The thing that you were missing is React-Redux API, you should probably explore it more because it already contemplates a lot of this use cases

所以,React-Redux 的connect 函数的第一个参数叫做mapStateToProps.

So, React-Redux's connect function's first parameter is called mapStateToProps.

这是它的签名:

mapStateToProps(state, [ownProps]): stateProps

我想说的是 ownProps 参数.

ownProps 包含传递给连接组件的所有道具.

ownProps contains all the props that are passed to your connected component.

只是为了澄清,你有这些组件

Just for clarification, you have these components

  • 常规组件:即 StatementLineItemDesktopBase
  • 连接组件:即ConnectedBase = connect(mapStateToProps)(Base)

因此,根据此信息,名为 FormItemsValueSelectorHOC 的 HOC 函数返回 ConnectedBase 的变体.

So, from this information, your HOC function called FormItemsValueSelectorHOC returns a variation of ConnectedBase.

因此,无论您传递给 ConnectedBase 的任何道具或从 FormItemsValueSelectorHOC 返回的任何组件,您都可以从 ownProps

So, whatever props you pass to ConnectedBase or whatever component it's returned from FormItemsValueSelectorHOC you can access them from ownProps

顺便说一句,在您的特定情况下,这是您的 mapStateToProps

BTW, in your particular case, this is your mapStateToProps

function mapStateToProps(state, ownProps) {
  const formName = ownProps.formName;
  const selector = formValueSelector(formName);
  const items = selector(state, 'items');
  return {
    items
  };
}

需要注意的是,connect 也是一个 HOC,所以逻辑上认为你用普通组件做的大部分事情你也可以用连接的组件做,我会建议您阅读 connect 源代码,它不长也不难,因此您可能会探索和理解此答案的更多内容.

The thing to Note is that connect is also an HOC, so it's logically to think that most of the things you do with normal components you will also be able to do with connected Components, I would suggest for you to read the connect source, it's not long nor difficult so you can probably explore and comprehend more of this answer.

我希望这会有所帮助.

这篇关于调用高阶组件时,在 React 类之外访问 prop的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆