我正在寻找使用React进行开发的合适模式/方式,但是到目前为止,我没有发现任何相关的/优雅的方法。
我基本上想写一个表单引擎。对于表单的每个输入,我都希望有一些通用的行为。
我在React文档中读到,继承不是正确的方法。最好的方法是设计通用组件并按组成对其进行专门化。
在我的顶级组件中,我想写一些类似的东西:
<Form>
<TextInput .../>
<TextInput .../>
<EmailInput .../>
</Form>
每种类型的输入基本上都必须做同样的事情:例如:对照验证器检查此值,等等。
因此,我设计了一个通用组件FormInput
,其中包含所有这些标准行为。当我编写TextInput
组件时,外观如下:
export default class TextInput extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<FormInput>
<input name={this.props.name}
type='text'
onChange={this.onChange}
onBlur={this.dirty}
value={this.state.value}
/>
</FormInput>
);
}
}
现在,麻烦在于this.onChange
或this.dirty
是FormInput
组件中的标准行为,因此很显然,我不能像这样直接访问它们……>
将已包含的内容连接到其容器组件的正确方法是什么?
编辑
仅是为了澄清和总结目标,我基本上想制作一个通用组件和一个包含在内的内容/模板。问题是我需要将特定的DOM模板(位于特定的组件中)绑定到通用处理程序(位于通用的组件中)。
预先感谢!
答案 0 :(得分:0)
如果我理解正确,那么您的onChange
和dirty
方法是在FormInput组件内部实现的。在这种情况下,input
元素应放置在组件的render方法内,而不应作为子元素传递。
该FormInput
渲染方法应如下所示:
render(){
return <input name={this.props.name}
type={this.props.type}
onChange={this.onChange}
onBlur={this.dirty}
value={this.state.value}
/>
}
另外FormInput
应该具有名称和类型属性才能以这种方式使用它:
<FormInput name='A name' type='text' />
我想,起初,您正试图传递与其他html元素包装在一起的输入的可能性。如果是这样的话,就我的建议而言,您只需包装新的FormInput即可获得相同的结果。
更新:
要在FormInput组件内渲染其他类型的表单元素,并且如果您对条件渲染不满意,可以尝试其他方法,在类型为prop的渲染内使用createElement
方法。 / p>
更多信息在这里: Create Element
我以前使用过它,并且在我的项目中做得很好。
答案 1 :(得分:0)
根据您的评论:
FormInput
必须托管所有标准内容,例如更改和验证。TextInput
基本上只能托管html<input>
标签及其样式。
在我看来,您的等级制度是错误的。
我将创建一个Input
来负责原语input
的外观,并创建一个Form
来负责嵌套input
的行为以及它们所包含的数据。
这是一个运行中的示例,显然您可以用其他方式设置样式,而不是内联样式。
const Input = ({ label, ...rest }) => (
<div style={{ display: "flex" }}>
<div style={{ display: "flex", alignItems: "center", margin: "10px 0" }}>
<label style={{ minWidth: "100px", margin: "0 10px" }}>{label}</label>
<input style={{ padding: "0.5em" }} {...rest} />
</div>
</div>
);
class Form extends React.Component {
state = {
fName: "",
lName: "",
age: null
};
onChange = e => {
const { name, value } = e.target;
this.setState({ [name]: value });
};
onSubmit = e => {
e.preventDefault();
const { onSubmit } = this.props;
onSubmit(this.state);
};
render() {
const { fName, lName, age } = this.state;
return (
<form onSubmit={this.onSubmit}>
<Input
type="text"
name="fName"
label="First Name"
value={fName}
required
onChange={this.onChange}
/>
<Input
type="text"
name="lName"
label="Last Name"
value={lName}
required
onChange={this.onChange}
/>
<Input
type="number"
name="age"
label="Age"
value={age}
required
onChange={this.onChange}
/>
<button type="submit">Submit</button>
</form>
);
}
}
function App() {
return (
<div>
<Form onSubmit={data => console.log(data)} />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
答案 2 :(得分:0)
我终于知道了!
这是我的解决方案:
export default class TextInput extends React.Component {
constructor(props) {
super(props);
}
template(state, formInput) {
return (
<input name={this.props.name}
type='text'
onChange={formInput.onChange}
onBlur={formInput.dirty}
value={state.value}/>
);
}
render() {
return (
<FormInput {...this.props} template={this.template} />
);
}
}
终于比预期的要容易,但是我没有使用包容性。
FormInput
组件托管从状态到通用代码/行为(如dirty
或onChange
)的所有内容。
TextInput
组件仅实例化一个FormInput
并托管一个名为template
的函数,该函数采用远程状态和通用FormInput
组件本身来访问其功能。 / p>
然后在FormInput
中,我得到以下信息:
render() {
return this.props.template(this.state, this);
}
通用输入组件调用template
函数,并传递呈现所需的内容。
这样,我将视图与行为分离了。
希望您会喜欢它,以后对您有所帮助;)