ReactJS:通过表单获取和更新数据的惯用方式是啥?

Posted

技术标签:

【中文标题】ReactJS:通过表单获取和更新数据的惯用方式是啥?【英文标题】:ReactJS: What is the idiomatic way to fetch and update data through a form?ReactJS:通过表单获取和更新数据的惯用方式是什么? 【发布时间】:2015-07-23 20:18:50 【问题描述】:

我正在努力思考通过 html 表单更新数据的最佳方法。以 ReactJS 网页为例:

https://facebook.github.io/react/docs/tutorial.html

假设您希望实现让用户编辑她过去发布的评论的功能(即不在当前会话中,因此必须从服务器获取)。编辑评论页面需要预先填写评论的现有作者姓名和文本。您将如何实现获取评论数据和预填写评论表单?以下是我脑海中无法理清的相互矛盾的想法(我们称新组件为CommentEdit):

最初的评论作者和文字应该是CommentEdit的道具,因为它们不是状态 CommentEdit 组件应该是可重用的,因此它应该能够从服务器本身获取初始数据,但随后必须将其保存为状态 如果 CommentEdit 的父级要获取并设置 CommentEdit 的 props,则必须将其保存为状态,因此没有太多节省 Flux 之类的东西可能会起作用,但 Flux 让我更加困惑。如果 Flux 要存储 cmets,它是否必须为用户保存每条评论?如果用户有数千个 cmets 会发生什么?

老实说,我只是希望组件可以更改自己的道具。似乎它会使组件更加可重用。

【问题讨论】:

【参考方案1】:

老实说,我只是希望组件可以更改自己的道具。似乎它会使组件更加可重用。

并非如此,可以更改自己的 props 的组件并不比那些不能更改的组件更可重用,只是它们的底层实现会变得更加复杂。

当前react.js 流与数据下降和事件冒泡使组件“非常”确定性,因为在组件生命周期中的任何时候,您都知道组件将根据您给它的输入生成什么输出。这在调试和单元测试应用程序时也很有帮助。

现在,让您进退两难的是,CommentEdit 只需要一个content 属性,因为作者不会更改,并且始终是登录网站的人。其他状态不是必需的,因为当用户单击save 按钮时,编辑的内容会冒泡,并且当存储在组件祖先之一的state 中的comments 列表将插入列表时更新。

如果您为每个评论正确设置了key 属性,那么react 会很好地注意到已编辑评论的html 元素不需要重新创建,只需渲染html 元素的innerHTML评论需要更改。

如果您想显示作者,可以将其添加为道具,除非您想使用此布局构建多个站点,否则它不会影响/改进组件本身。

【讨论】:

感谢您的回复。虽然在这种情况下content 是唯一的属性,但如果组件有很多属性怎么办?这不会要求父组件保持其状态的所有属性吗? 根据数据模型和 UI,子组件的属性可能需要从状态中检索,或者可以从自己的属性中推断出来。它仍然是一种更简洁的设计,因为数据仅在一个方向流动,这使您的应用程序架构更加健壮。【参考方案2】:

我最终通过为我的每个组件添加一个“包装器”父级来解决这个问题。包装器组件负责从服务器获取数据,并将其存储在其状态中。包装器会将获取的状态作为道具传递给它的孩子。然后我将这个设置抽象为 mixin,创建了一个包装混合和包装子混合,以便我可以轻松地重用这个设置。

这种模式非常适用于您应用中的典型表单。包装器将获取数据以预填充表单,子节点将表单发送到服务器并负责错误处理。

这是一个例子:

// This handles the form submission and error handling
var EditFormMixin = 
  getInitialState: function() 
    return formState:FORM_STATE_EDITING, errors:
  ,
  handleSubmitBase: function(event, url, data, method, success, error) 
    event.preventDefault();
    this.setState(formState:FORM_STATE_SUBMITTING, errors:);
    $.ajax(
        url: url,
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        data: JSON.stringify(data),
        method: method,
        success: function(data) 
            this.setState(formState:FORM_STATE_SUBMITTED);
            if (success) 
                success();
            ;
        .bind(this),
        error: function(xhr, status, err) 
            this.setState(formState:FORM_STATE_EDITING);
            if (xhr.status == 400) 
                this.setState(errors:xhr.responseJSON);
            
            if (error) 
                error();
            
        .bind(this)
    );
  
;

// This handles fetching the initial data for the form
var EditFormWrapperMixin = 
  getInitialState: function() 
    return data: , loadState:LOAD_STATE_UNLOADED, url:this.getUrl();
  ,
  fetch: function() 
    this.setState(loadState:LOAD_STATE_LOADING)
    $.ajax(
        url: this.state.url,
        dataType: "json",
        method: "GET",
        success: function(data) 
            this.setState(data:data, loadState:LOAD_STATE_LOADED);
        .bind(this),
        error: function(xhr, status, err) 
        .bind(this)
    );
  
  componentDidMount: function() 
    this.fetch();
  ,
  componentWillReceiveProps: function(nextProps) 
    var url = this.getUrl();
    this.setState(url:url, function() 
        this.fetch();
    );
  
;

【讨论】:

【参考方案3】:

Flux 是您可以用来从应用程序中获取数据的最佳工具,您不必在组件内部使用状态,使用 props 来收取初始数据,然后使用 react.DOMNode 从每个元素中获取数据你需要https://facebook.github.io/react/docs/top-level-api.html#react.finddomnode的表单,在所有表单组件中也使用refs,最后你可以使用flux将你的数据发送到服务器并保存。

【讨论】:

以上是关于ReactJS:通过表单获取和更新数据的惯用方式是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在 reactjs 中使用表单并获取请求时出现问题

如何在 reactjs 16.8 中获取 refetchQueries 数据

生成和管理后台线程的惯用 Clojure 方式

通过引用遍历节点的惯用方式

ReactJS 与数据库的连接

如何通过jQuery / Javascript获取更新的表单输入值?