在调用高阶组件时,在React中访问类之外的prop

时间:2022-08-22 21:56:10

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.

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

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.

formValueSelector需要一个引用表单名称的sting。我想动态设置它,并且只要我需要项目的值,就可以使用这个HOC。我使用项目值进行计算。

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传递了组件和字符串。我想将它设置为从父(表单)传入的prop formName。

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

我是HOC模式的新手,所以任何提示都会非常感激。

HOC

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;

Wrapped Component

包裹的组件

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');

1 个解决方案

#1


4  

TLDR: use ownProps parameter

TLDR:使用ownProps参数

Draft of what you should do

你应该做什么的草案

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);

And this will be the way you use it

这将是你使用它的方式

<ConnectedStatementLineItemDesktop formName={"editQuote"} />

Let me explain a bit more how this work

让我再解释一下这项工作的进展情况

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 API,您应该更多地探索它,因为它已经考虑了很多这样的用例

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

因此,React-Redux的connect函数的第一个参数称为mapStateToProps。

This is its signature:

这是它的签名:

mapStateToProps(state, [ownProps]): stateProps

The thing that I want to remark is the ownProps parameter.

我要注意的是ownProps参数。

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

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

Just for clarification, you have these components

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

  • Regular Component: i.e. StatementLineItemDesktop and Base
  • 常规组件:即StatementLineItemDesktop和Base
  • Connected Component: i.e. ConnectedBase = connect(mapStateToProps)(Base)
  • 连接组件:即ConnectedBase = connect(mapStateToProps)(Base)

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

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

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

因此,无论您传递给ConnectedBase的道具还是从FormItemsValueSelectorHOC返回的任何组件,您都可以从ownProps访问它们

BTW, in your particular case, this is your mapStateToProps

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

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

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.

需要注意的是,connect也是一个HOC,所以逻辑上认为你使用普通组件做的大部分事情也可以用连接组件做,我建议你阅读连接源,它是不长也不困难,所以你可以探索和理解更多这个答案。

I hope this helped.

我希望这有帮助。

#1


4  

TLDR: use ownProps parameter

TLDR:使用ownProps参数

Draft of what you should do

你应该做什么的草案

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);

And this will be the way you use it

这将是你使用它的方式

<ConnectedStatementLineItemDesktop formName={"editQuote"} />

Let me explain a bit more how this work

让我再解释一下这项工作的进展情况

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 API,您应该更多地探索它,因为它已经考虑了很多这样的用例

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

因此,React-Redux的connect函数的第一个参数称为mapStateToProps。

This is its signature:

这是它的签名:

mapStateToProps(state, [ownProps]): stateProps

The thing that I want to remark is the ownProps parameter.

我要注意的是ownProps参数。

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

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

Just for clarification, you have these components

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

  • Regular Component: i.e. StatementLineItemDesktop and Base
  • 常规组件:即StatementLineItemDesktop和Base
  • Connected Component: i.e. ConnectedBase = connect(mapStateToProps)(Base)
  • 连接组件:即ConnectedBase = connect(mapStateToProps)(Base)

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

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

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

因此,无论您传递给ConnectedBase的道具还是从FormItemsValueSelectorHOC返回的任何组件,您都可以从ownProps访问它们

BTW, in your particular case, this is your mapStateToProps

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

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

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.

需要注意的是,connect也是一个HOC,所以逻辑上认为你使用普通组件做的大部分事情也可以用连接组件做,我建议你阅读连接源,它是不长也不困难,所以你可以探索和理解更多这个答案。

I hope this helped.

我希望这有帮助。