使用助焊剂时的表格验证

hgu*_*ser 5 javascript flux

我在我的应用程序中使用flux,我Backbone.View用作视图层.

通常有一个存储实例整个页面,该店保存应用程序的数据(或国家),和视图将监听器change的事件store中,当store触发一个change事件,该视图会相应重新渲染本身.

到目前为止好,但我遇到了一些问题,当我使用的形式,在使用时尽量提交表单或blur事件触发的元素,我想以验证服务器的输入,并尽快显示错误,这就是我所做的:

  1. 当用户点击提交按钮或为元素更改的值时,我将调度如下操作: dispatch({type:"validate",value:"value"});

  2. store将这一行动作出反应,并发送请求给服务器

  3. 当响应返回时,我将更新商店并触发change事件: store.validate_response=response; store.trigger("change");

  4. 视图(示例中的表单)将重新呈现自身.

我可以显示错误,但我不能保留元素的值,因为表单中的元素被重新渲染,这意味着它们将显示原始值而不是用户键入的值.

我认为在调度validate操作时也保存类型值,如下所示:

dispatch({type:"validate",value:"value",userTypedValueForEveryElement:"....."});
Run Code Online (Sandbox Code Playgroud)

当使用点击提交按钮时它起作用,因为一般当他们点击按钮时他们不会在表单中输入任何内容,但是这种情况怎么样:

<input type="text" id="A" />
<input type="text" id="B" />
Run Code Online (Sandbox Code Playgroud)

用户键入avalueinput A,然后键入bvinput B,在同一时间,我会做验证,并调度操作时同时发送的值:

{a:"avalue",b:"bv"}
Run Code Online (Sandbox Code Playgroud)

store会保留这些值.

和请求期间,用户继续键入的元素B,现在的价值bvalue,并在同一时间的验证响应返回,那么表单会重新渲染,这将设置avalueAbvB,这是一点,值了在B丢失,用户会感到惊讶,他们不知道发生了什么.

有什么想法解决这个问题?

看来这种flux方式:

view trigger action --> 
store respond to actions --> 
store trigger changed -->
view respond to store(re-render in most case) --> 
view trigger action" 
Run Code Online (Sandbox Code Playgroud)

使这种要求比以前复杂.一旦有很多交互式的视图,你将不得不做更多的额外工作来保持视图的状态.

这是真的还是因为我错过了什么?

Bre*_*non 1

听起来您在这里遇到了一些不同的问题,但它们都是可以解决的。这有点长,但希望它能解决您遇到的所有问题。

商店设计:首先,您的商店实际上要保存什么信息?尽量不要将 Flux 商店视为 Backbone Model,因为它们的用途并不完全相同。Flux 存储应该存储应用程序状态的一部分(不一定是 UI 组件状态的一部分),并且不应该知道或关心使用它的任何视图。牢记这一点可以帮助您将行为和数据放在正确的位置。假设您的商店正在跟踪用户在特定表单中的输入。由于您的应用程序关心输入是否有效,因此您需要以某种方式在存储中表示它。您可以将每个输入表示为存储中的一个对象,例如{val: 'someInput', isValid: false}. 无论您如何存储它,它都必须在那里;应用程序的任何部分都应该能够从商店中提取数据并知道哪些输入有效/无效。

我同意 @korven 的观点,即在 Store 中放置大量应用程序逻辑是一个糟糕的选择。我将 AJAX 调用放入操作创建逻辑中,并使用 AJAX 响应回调在 Dispatcher 上创建实际操作;我已经不止一次看到这个推荐了。

保留用户输入:一方面,您只想在用户完成输入时呈现表单输入 - 否则,呈现将在用户输入时更改文本。这很简单——节流反跳对用户输入事件的输入验证处理程序进行(如果您使用焦点或模糊事件,计时不太可能成为问题,但您仍然应该考虑它。)仅在验证完成后才更新商店。当然,仅在商店更新时渲染。因此,只有当用户停止输入并且我们已经验证了他们的输入时,我们才会修改 DOM 中的输入值。

即使使用限制/去抖动,由于验证请求是异步的,并且用户可能(可能)在短时间内触发许多验证请求,因此您不能依赖按顺序返回的响应。换句话说,您无法在每个响应返回时对其进行处理;如果它们不按顺序返回,您将用旧输入覆盖最近的输入。(我在现实生活中遇到过这个问题。这对你来说可能是一个边缘情况,但当它发生时,错误会很混乱,值得预先解决。)幸运的是,我们只关心用户最近输入的内容。因此,除了最近请求的响应之外,我们可以忽略对验证请求的所有响应。通过跟踪每个请求的“密钥”,您可以轻松地将此逻辑与发出请求的任何内容集成。这是我如何解决这个问题的示例:

// something in your view
this.on(keyup, function() {
  var input = this.getUserInput();
  validationService.validate(input);
}

// within validationService
validate: function(input) {
  // generate random int between 1 and 100
  var randKey = Math.floor(Math.random() * (100 - 1)) + 1;
  this.lastRequestKey = randKey;
  this.doAjaxRequest({
    data: {input: input},
    callback: function() {
      if (randKey !== this.lastRequestKey) {
        // a newer request has modified this.lastRequestKey
        return;
      }
      // do something to update the Store 
  });
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,负责验证服务的对象仅“记住”最近为请求设置的“密钥”。由于其闭包,每个回调在范围内都有其原始密钥,并且它可以检查其原始密钥是否等于服务对象上设置的密钥。如果没有,那就意味着发生了另一个请求,我们不再关心这个响应。您需要为每个字段设置“键”,以便对字段 B 的新请求不会覆盖对字段 A 的旧请求。您可以通过其他方式解决此问题,但要点是,丢弃除对任何给定输入的最后一个请求的响应。这样做的额外好处是可以在那些被丢弃的响应上节省一些更新/渲染周期。

多字段渲染:当您正确执行 Flux 时,您永远不应该“丢失”数据,因为所有更改都来自 Dispatcher/Store,并且在前一个更新完全完成之前 Dispatcher 不会向存储发送新的更新。因此,只要您使用每个新输入更新商店,您就不会丢失任何内容。您不必担心输入 B 的更改会导致您丢失正在进行的输入 A 的更改,因为输入 A 的更改将从 Dispatcher 流向 Store,再流向 View并完成渲染 ,并在 Dispatcher 之前将允许对输入 B 的更改开始处理。(这意味着渲染应该很快,因为它们会阻塞下一个操作。React 与 Flux 配合良好的原因之一。)

只要您将所有内容放入存储中,并且不要将错误的内容放入存储中(上面的输入和异步处理内容所处理的内容),您的 UI 就会是准确的。Flux 模式将每个更改视为一个原子事务,保证在下一个更改发生之前完成。