调用高阶组件时在 React 中访问 class 之外的 prop
Access prop outside of class in React when calling Higher Order Component
我正在尝试使用高阶组件 (HOC) 模式来重用一些连接到状态并使用 Redux Form formValueSelector 方法的代码。
formValueSelector 需要引用表单名称的字符串。我想动态地设置它,并能够在我需要项目的值时使用这个 HOC。我使用项目值进行计算。
在下面的代码中,HOC 传递了组件和字符串。我想将其设置为从父级(表单)传入的道具 formName。
我是 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;
包装组件
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
参数
你应该做什么的草案
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;
这将是您创建连接组件的方式
formItemsValueSelectorHOC(StatementLineItemDesktop);
这将是您使用它的方式
<ConnectedStatementLineItemDesktop formName={"editQuote"} />
让我再解释一下这是如何工作的
你错过的是 React-Redux API,你可能应该更多地探索它,因为它已经考虑了很多这样的用例
因此,React-Redux 的 connect
函数的第一个参数被称为 mapStateToProps
。
这是它的签名:
mapStateToProps(state, [ownProps]): stateProps
我要说明的是ownProps
参数。
ownProps
包含传递给连接组件的所有道具。
澄清一下,您有这些组件
- 常规组件:即
StatementLineItemDesktop
和 Base
- 连通分量:即
ConnectedBase = connect(mapStateToProps)(Base)
因此,根据此信息,您的 HOC 函数称为 FormItemsValueSelectorHOC
returns ConnectedBase
.
的变体
因此,无论您传递给 ConnectedBase
的任何道具或从 FormItemsValueSelectorHOC
返回的任何组件,您都可以从 ownProps
访问它们
顺便说一句,在您的特定情况下,这是您的 mapStateToProps
function mapStateToProps(state, ownProps) {
const formName = ownProps.formName;
const selector = formValueSelector(formName);
const items = selector(state, 'items');
return {
items
};
}
需要注意的是 connect
也是一个 HOC,所以从逻辑上讲,你可以用普通组件做的大部分事情你也可以用连接的组件做,我建议供您阅读 connect
来源,它不长也不难,因此您可以探索和理解更多此答案。
希望对您有所帮助。
我正在尝试使用高阶组件 (HOC) 模式来重用一些连接到状态并使用 Redux Form formValueSelector 方法的代码。
formValueSelector 需要引用表单名称的字符串。我想动态地设置它,并能够在我需要项目的值时使用这个 HOC。我使用项目值进行计算。
在下面的代码中,HOC 传递了组件和字符串。我想将其设置为从父级(表单)传入的道具 formName。
我是 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;
包装组件
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
参数
你应该做什么的草案
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;
这将是您创建连接组件的方式
formItemsValueSelectorHOC(StatementLineItemDesktop);
这将是您使用它的方式
<ConnectedStatementLineItemDesktop formName={"editQuote"} />
让我再解释一下这是如何工作的
你错过的是 React-Redux API,你可能应该更多地探索它,因为它已经考虑了很多这样的用例
因此,React-Redux 的 connect
函数的第一个参数被称为 mapStateToProps
。
这是它的签名:
mapStateToProps(state, [ownProps]): stateProps
我要说明的是ownProps
参数。
ownProps
包含传递给连接组件的所有道具。
澄清一下,您有这些组件
- 常规组件:即
StatementLineItemDesktop
和Base
- 连通分量:即
ConnectedBase = connect(mapStateToProps)(Base)
因此,根据此信息,您的 HOC 函数称为 FormItemsValueSelectorHOC
returns ConnectedBase
.
因此,无论您传递给 ConnectedBase
的任何道具或从 FormItemsValueSelectorHOC
返回的任何组件,您都可以从 ownProps
顺便说一句,在您的特定情况下,这是您的 mapStateToProps
function mapStateToProps(state, ownProps) {
const formName = ownProps.formName;
const selector = formValueSelector(formName);
const items = selector(state, 'items');
return {
items
};
}
需要注意的是 connect
也是一个 HOC,所以从逻辑上讲,你可以用普通组件做的大部分事情你也可以用连接的组件做,我建议供您阅读 connect
来源,它不长也不难,因此您可以探索和理解更多此答案。
希望对您有所帮助。