Javascript 尝试在React中构建泛型表单组件而不使用eval()

Javascript 尝试在React中构建泛型表单组件而不使用eval(),javascript,reactjs,forms,Javascript,Reactjs,Forms,我目前正试图为我的React应用程序编写一个通用表单组件。我知道有很多很好的图书馆,但在这一点上,它们对我来说似乎都是小题大做 我在这里的主要目标是通过将提交函数作为道具传递,并将输入字段和按钮作为子项传递,以及每个字段的验证要求,获得一个我可以使用的组件 我的组件应该处理表单状态,onChange,onBlur,onSubmit等,还应该处理验证(基于我添加为子项的每个输入类型) 其动机是每当需要创建一个新表单时,我都会感觉到重复,因为必须反复管理输入、验证、onChange和submit函数

我目前正试图为我的React应用程序编写一个通用表单组件。我知道有很多很好的图书馆,但在这一点上,它们对我来说似乎都是小题大做

我在这里的主要目标是通过将提交函数作为
道具
传递,并将输入字段和按钮作为
子项
传递,以及每个字段的验证要求,获得一个我可以使用的
组件

我的
组件应该处理表单
状态
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的
时,代码变得更加明确。谢谢很高兴这有帮助。