首页 > 解决方案 > 尝试在不使用 eval() 的情况下在 React 中构建通用表单组件

问题描述

我目前正在尝试为我的 React 应用程序编写通用表单组件。我知道那里有很多很棒的库,但在这一点上,它们对我来说似乎都是矫枉过正。

我的主要目标是拥有一个<BasicForm>我可以使用的组件,方法是传递提交函数props并传递输入字段和按钮,就像children每个字段的验证要求一样。

我的<BasicForm>组件应该处理表单state, onChange, onBlur,onSubmit等。还应该处理验证(基于我添加为的每个输入类型children)。

动机是每次需要创建新表单时,我都会感到重复,因为必须一遍又一遍地管理state输入、验证onChange和功能。submit

这是我正在使用的代码<Basic Form>

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>

我最初并没有在这里添加源代码,<BasicForm>以免这个问题太长,但基本上它处理所有输入childrenReact.Children.map并且它具有每种输入的验证功能,以及处理更改、模糊、提交的功能,等等。它还state为每个输入字段创建一个。

问题介绍

  <BasicForm
    submitFunction={props.linkEmailAndPassword}
    submitAction={'this.props.submitFunction(this.state.passwordOne)'}
  >

从上面的代码片段中可以看出,为了将submitAction消费者发送到<BasicForm>,我必须将它包装在一个字符串中,因为它引用的 astate只存在于<BasicForm>. 最重要的state是,我需要提交的特定部分是在<BasicForm>(在消费者中)之外定义的。

消费者定义应该提交的部分或部分,state并且在每种情况下都会有所不同,因此我不能将其作为state任何<BasicForm>内置的“通用”名称。

所以我作为字符串发送,在里面<BasicForm>我必须使用最不推荐eval()的,如下所示:

BasicForm.js

  onSubmit(event) {
    event.preventDefault();
    this.validateAllFields();
    eval(this.props.submitAction);
  }

正确的问题

eval()在这种情况下有多糟糕?我这样做是否会将我的应用程序暴露给“恶意黑客”?我是否应该以任何方式对其进行消毒,即使它不是用户输入?还有其他方法吗?我真的很高兴不必每次需要时都从头开始构建表单。现在我只关注字段和验证要求。谢谢你的时间!

额外信息

PS:这是输入组件之一的代码TextInputPasswordInput非常像这样。唯一的区别是type='password'

文本输入.js

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;

标签: javascriptreactjsforms

解决方案


Eval 几乎从不受欢迎,因为它会带来安全风险、性能损失并表明存在设计问题。

是否存在安全风险取决于其使用情况。如果评估的表达式有可能直接或间接包含用户输入,则存在安全风险。否则,仅适用于性能和设计问题。

在这种情况下,这意味着BasicForm未能为父组件提供合理的 API,因此以eval. 执行此操作的正确方法是回调。

由于父组件通常不应了解BasicForm实现细节并访问其实例,BasicForm this因此不应在回调中可用。BasicForm道具已经在回调中可用 - 它们在父组件中传递。由于已知它BasicForm state包含来自其子输入的值,因此它应该在回调中可用。

所以BasicForm回调可能看起来像:

  <BasicForm
    onSubmit={state => props.linkEmailAndPassword(state.passwordOne)}}

  ...

  onSubmit(event) {
    event.preventDefault();
    this.validateAllFields();
    this.props.onSubmit(this.state);
  }

如果需要onSubmit回调来访问BasicForm其状态以外的任何数据,这意味着该数据也应作为回调参数传递。


推荐阅读