[英]React: Is it possible to call a higher-order component within a container component?
在我的代码库中,我有一个高阶组件(HOC),可用于将所有输入验证功能添加到给定组件。 在像这样的已定义组件上使用时,它效果很好。
let NameInput = React.createClass({
render() {
return (
<div>
<label htmlFor="name-input">Name</label>
<input name="name-input" />
</div>
);
}
});
let NameInput = addInputValidation(NameInput);
module.exports = NameInput;
但是我现在需要基于服务器上的数组定义一系列输入。 像这样
let TestApp = React.createClass({
render() {
// Pretend the names array came from the server and is actually an array of objects.
let names = ['First name', 'Middle name', 'Last name'];
// Map over our names array in hopes of ending up with an array of input elements
let nameComponents = names.map((name, index) => {
let componentToRender = (
<div key={index}>
<label htmlFor={name}>{name}</label>
<input name={name} />
</div>
);
// Here is where I'd like to be able to use an HOC to wrap my name inputs with validation functions and stuff
componentToRender = addInputValidation(componentToRender);
return componentToRender;
})
return (
<div>
<p>Enter some names:</p>
{nameComponents}
</div>
);
}
})
let addInputValidation = function(Component) {
let hoc = React.createClass({
getInitialState() {
return {
isValid: false
};
},
render() {
return (
<div>
<Component {...this.props} />
{this.state.isValid ? null : <p style={{color: "red"}}>Error!!!!</p>}
</div>
);
}
});
return hoc;
}
module.exports = TestApp;
当您尝试呈现从另一个组件内部调用HOC的结果时,React不喜欢它。
我认为这与我的componentToRender
实际上不是一个React组件无关。
所以我的问题是
为什么不能从另一个组件中调用HOC?
有没有一种方法可以在数组的每个元素上调用HOC?
这是一个可能有用的jsfiddle: https ://jsfiddle.net/zt50r0wu/
编辑以澄清某些事情:
我映射到的数组实际上是描述输入细节的对象数组。 包括输入类型(选择,复选框,文本等)。
另外,我的addInputValidation
HOC实际上接受的参数不仅仅是组件。 它需要一个将从Redux存储拉出的存储索引数组,以用于验证。 这些存储索引来自描述输入的对象数组中的信息。 可以访问此潜在动态数组是我希望能够在React生命周期内调用HOC的原因。
因此,在我的输入数组上进行映射可能看起来像这样……
let Select = require('components/presentational-form/select');
let Text = require('components/presentational-form/select');
let CheckboxGroup = require('components/presentational-form/select');
let TestApp = React.createClass({
render() {
// Pretend the inputs array came from the server
let inputs = [{...}, {...}, {...}];
// Map over our inputs array in hopes of ending up with an array of input objects
let inputComponents = inputs.map((input, index) => {
let componentToRender = '';
if (input.type === 'select') {
componentToRender = <Select labelText={input.label} options={input.options} />;
} else if (input.type === 'text') {
componentToRender = <Text labelText={input.label} />;
} else if (input.type === 'checkbox') {
componentToRender = <CheckboxGroup labelText={input.label} options={input.options} />;
}
// Here is where I'd like to be able to use an HOC to wrap my name inputs with validation functions and stuff
componentToRender = addInputValidation(componentToRender, input.validationIndexes);
return componentToRender;
})
return (
<div>
<p>Enter some names:</p>
{inputComponents}
</div>
);
}
})
关于您的编辑:问题仍然在于,您正在从.map
回调中返回组件而不是元素。 但这可以通过更改轻松地解决
return componentToRender;
至
return React.createElement(componentToRender);
您的代码中的问题是:
addInputValidation
期望传递一个组件,但是您传递给它一个元素 ( <div />
)。 看来解决问题的最简单方法是创建一个通用的Input
组件,该组件接受名称和值作为prop:
let Input = React.createClass({
render() {
return (
<div>
<label htmlFor={this.props.name}>{this.props.name}</label>
<input name={this.props.name} />
</div>
);
}
});
module.exports = addInputValidation(Input);
用作
let nameComponents = names.map((name, index) => <Input key={index} name={name} />);
我认为您要克服的是组件与元素之间的区别。 我发现将组件视为功能,并将元素视为该功能的结果很有帮助。 因此,您真正要做的就是有条件地选择三个不同功能之一,将其传递一些参数,然后显示结果。 我相信您想要这样的东西:
(顺便说一句,可以清理一下,只是尝试尽可能地保留您的代码结构)
let Select = require('components/presentational-form/select');
let Text = require('components/presentational-form/select');
let CheckboxGroup = require('components/presentational-form/select');
let TestApp = React.createClass({
render() {
// Pretend the inputs array came from the server
let inputs = [{...}, {...}, {...}];
// Map over our inputs array in hopes of ending up with an array of input objects
let inputComponents = inputs.map((input, index) => {
let ComponentToRender;
let props;
if (input.type === 'select') {
ComponentToRender = addInputValidation(Select);
props = { labelText: input.label, options: input.options };
} else if (input.type === 'text') {
ComponentToRender = addInputValidation(Text);
props = { labelText: input.label };
} else if (input.type === 'checkbox') {
ComponentToRender = addInputValidation(CheckboxGroup);
props = { labelText: input.label, options: input.options };
}
let element = <ComponentToRender {...props} />;
return element;
})
return (
<div>
<p>Enter some names:</p>
{inputComponents}
</div>
);
}
})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.