Javascript 尝试在React中构建泛型表单组件而不使用eval()
我目前正试图为我的React应用程序编写一个通用表单组件。我知道有很多很好的图书馆,但在这一点上,它们对我来说似乎都是小题大做 我在这里的主要目标是通过将提交函数作为Javascript 尝试在React中构建泛型表单组件而不使用eval(),javascript,reactjs,forms,Javascript,Reactjs,Forms,我目前正试图为我的React应用程序编写一个通用表单组件。我知道有很多很好的图书馆,但在这一点上,它们对我来说似乎都是小题大做 我在这里的主要目标是通过将提交函数作为道具传递,并将输入字段和按钮作为子项传递,以及每个字段的验证要求,获得一个我可以使用的组件 我的组件应该处理表单状态,onChange,onBlur,onSubmit等,还应该处理验证(基于我添加为子项的每个输入类型) 其动机是每当需要创建一个新表单时,我都会感觉到重复,因为必须反复管理输入、验证、onChange和submit函数
道具
传递,并将输入字段和按钮作为子项
传递,以及每个字段的验证要求,获得一个我可以使用的
组件
我的
组件应该处理表单状态
,onChange
,onBlur
,onSubmit
等,还应该处理验证(基于我添加为子项的每个输入类型)
其动机是每当需要创建一个新表单时,我都会感觉到重复,因为必须反复管理输入、验证、onChange
和submit
函数的state
这是我使用
的代码:
BasicForm Consumer.js
<BasicForm
submitFunction={props.linkEmailAndPassword}
submitAction={'this.props.submitFunction(this.state.passwordOne)'}
>
<PasswordInput
labelText='Password'
name='passwordOne'
placeholder='Enter password...'
min={6}
max={12}
required
/>
<TextInput
labelText='Username'
name='username'
placeholder='Enter username...'
initialValue=''
min={5}
max={10}
required
/>
<button type='submit'>Create Password</button>
</BasicForm>
onSubmit(event) {
event.preventDefault();
this.validateAllFields();
eval(this.props.submitAction);
}
import React from 'react';
import Label from './Common/Label';
const TextInput = (props) => {
return(
<div>
<Label
name={props.name}
labelText={props.labelText}
>
</Label>
<div>
<input
type='text'
id={props.name}
name={props.name}
placeholder={props.placeholder}
value={props.value}
onChange={props.onChange}
onBlur={props.onBlur}
>
</input>
</div>
{props.isInvalidMsg && <div><span>{props.isInvalidMsg}</span></div>}
</div>
);
};
export default TextInput;
正如您从上面的代码片段中看到的,为了将submitAction
从消费者发送到
,我必须将其包装为字符串,因为它引用的状态仅存在于
中。最重要的是,我需要提交的特定状态
部分是在
之外定义的(在消费者中)
消费者定义了应提交的状态
的一部分或多部分,并且在每种情况下都会有所不同,因此我不能将其作为任何
内置的“通用”状态
名称
因此,我以字符串形式发送,在
中,我不得不使用最不推荐的eval()
,如下所示:
BasicForm.js
<BasicForm
submitFunction={props.linkEmailAndPassword}
submitAction={'this.props.submitFunction(this.state.passwordOne)'}
>
<PasswordInput
labelText='Password'
name='passwordOne'
placeholder='Enter password...'
min={6}
max={12}
required
/>
<TextInput
labelText='Username'
name='username'
placeholder='Enter username...'
initialValue=''
min={5}
max={10}
required
/>
<button type='submit'>Create Password</button>
</BasicForm>
onSubmit(event) {
event.preventDefault();
this.validateAllFields();
eval(this.props.submitAction);
}
import React from 'react';
import Label from './Common/Label';
const TextInput = (props) => {
return(
<div>
<Label
name={props.name}
labelText={props.labelText}
>
</Label>
<div>
<input
type='text'
id={props.name}
name={props.name}
placeholder={props.placeholder}
value={props.value}
onChange={props.onChange}
onBlur={props.onBlur}
>
</input>
</div>
{props.isInvalidMsg && <div><span>{props.isInvalidMsg}</span></div>}
</div>
);
};
export default TextInput;
恰当的问题
在这种情况下,eval()
有多糟糕?通过这样做,我是否将我的应用暴露给“恶意黑客”?我是否应该以任何方式对其进行消毒,即使它不是用户输入?还有别的办法吗?我真的很高兴每次我需要一个表单的时候都不用从头开始构建表单。现在我只关注字段和验证需求。谢谢你的时间
额外信息
<BasicForm
submitFunction={props.linkEmailAndPassword}
submitAction={'this.props.submitFunction(this.state.passwordOne)'}
>
注意:这是其中一个输入组件的代码TextInput
。密码输入非常像这样。唯一的区别是type='password'
:
TextInput.js
<BasicForm
submitFunction={props.linkEmailAndPassword}
submitAction={'this.props.submitFunction(this.state.passwordOne)'}
>
<PasswordInput
labelText='Password'
name='passwordOne'
placeholder='Enter password...'
min={6}
max={12}
required
/>
<TextInput
labelText='Username'
name='username'
placeholder='Enter username...'
initialValue=''
min={5}
max={10}
required
/>
<button type='submit'>Create Password</button>
</BasicForm>
onSubmit(event) {
event.preventDefault();
this.validateAllFields();
eval(this.props.submitAction);
}
import React from 'react';
import Label from './Common/Label';
const TextInput = (props) => {
return(
<div>
<Label
name={props.name}
labelText={props.labelText}
>
</Label>
<div>
<input
type='text'
id={props.name}
name={props.name}
placeholder={props.placeholder}
value={props.value}
onChange={props.onChange}
onBlur={props.onBlur}
>
</input>
</div>
{props.isInvalidMsg && <div><span>{props.isInvalidMsg}</span></div>}
</div>
);
};
export default TextInput;
从“React”导入React;
从“./Common/Label”导入标签;
常量文本输入=(道具)=>{
返回(
{props.isinvalidsg&&{props.isinvalidsg}
);
};
导出默认文本输入;
Eval几乎从来都不受欢迎,因为它会带来安全风险、性能损失,并表明存在设计问题
如果存在安全风险,则取决于其用途。若计算表达式可能直接或间接包含用户输入,那个么就存在安全风险。否则,仅适用于性能和设计问题
在本例中,这意味着BasicForm
未能为父组件提供合理的API,因此它最终导致eval
。正确的方法是回调
由于父组件通常不应该知道BasicForm
实现细节并访问其实例,BasicForm
此
不应该在回调中可用BasicForm
props已经在回调中可用-它们在父组件中传递。由于已知BasicForm
state
包含来自其子输入的值,因此它应该在回调中可用
因此,BasicForm
回调可能如下所示:
<BasicForm
onSubmit={state => props.linkEmailAndPassword(state.passwordOne)}}
...
onSubmit(event) {
event.preventDefault();
this.validateAllFields();
this.props.onSubmit(this.state);
}
props.linkEmailAndPassword(state.passwordOne)}
...
提交(事件){
event.preventDefault();
这个.validateAllFields();
this.props.onSubmit(this.state);
}
如果需要onSubmit
回调来访问除状态之外的任何BasicForm
数据,这意味着该数据也应该作为回调参数传递。对于TextInput,为什么不使用名为props.type
的属性来更改类型。所以你不需要额外的密码输入或数字输入。@Gh05d我已经想到了。但由于我可能会以非常不同的方式验证密码、文本和数字,因此我决定为每种类型创建一个组件(我使用组件名称来区分它们)。此外,当您使用一个
和
而不是两个属性类型为text和number的
时,代码变得更加明确。谢谢很高兴这有帮助。