草庐IT

javascript - ReactJS表单组件的最佳实践

coder 2023-07-06 原文

我正在寻找使ReactJS组件负责用户编辑给定实体的表单的最佳实践。这里的例子非常简单。在许多情况下,实际的表单将具有更多的字段和更多的GUI功能。

React.createClass({
    getInitialState: function() {
        return {
            entity: {
                property1: null,
                property2: null
            }
        };
    },

    handleChange: function(e) {
        var entity = this.state.entity;

        switch(e.target.name) {
            case 'property1':
                entity.property1 = e.target.value;
                break;
            case 'property2':
                entity.property2 = e.target.value;
                break;
        }

        this.setState({
            entity: entity
        });
    },

    render: function() {
        return (
            <div className="entity-form">
                <form onChange={this.handleChange}>
                    <input type="text" name="property1" value={this.state.entity.property1} />
                    <br />

                    <textarea name="property2" value={this.state.entity.property2}></textarea>
                    <br />
                </form>
            </div>
        );
    }
});

表单的字段直接编辑实体对象,然后可以将其保存到RESTful api。我希望在用户更改字段时更新组件,以便GUI可以根据键入期间的输入使用react(例如验证,信息等)。

从理论上讲,我可以让整个状态对象代表正在编辑的实体,因此该实体的每个属性都是第一级状态变量。但是,我希望能够为GUI函数和与组件将要执行的操作有关的其他事情添加其他状态变量,因此我希望实体对象是一个状态变量,例如上面的“实体”状态变量。该对象当然可以是一些更复杂的对象,例如Backbone模型或类似对象,但是在此简化示例中,我仅使用具有所需属性的简单对象。

因此,在寻求为此目的制造React组件的最佳实践方法时,我有一些问题:
  • Prop 或状态。

  • 在这种情况下,我选择将带有表单内容的实体对象放在状态变量中而不是prop中。这是为了能够在表单输入期间更新对象,而不必调用父对象并更新 Prop 。就我的React经验而言,这将是此类表单组件的最佳实践。
  • 受控或不受控制的输入。

  • 在上面的简化示例中,我使用受控输入。这将导致在每次更改时更新状态并重新呈现组件(就像在文本字段中输入的每个字符一样)。这是最佳做法吗?好消息是,该组件可以完全控制发生的事情,而不是使用defaultValue参数,并且在某些事件(例如用户按下保存按钮)下,该组件可以提取值,更新实体并将其保存到服务器。对于在这种情况下应使用受控输入还是不受控制输入,是否有任何原因(或观点)?

    表单或每个输入的
  • onChange

    该示例在form标记上具有onChange,它使每次更改表单中的任何字段时都调用handleChange方法。但是,由于输入是受控的(具有值参数),因此React提示输入字段没有onChange属性。这是否意味着在表单标签上使用通用的onChange是不好的做法,我应该将其删除并将onChange放在每个单独的字段上?
  • 更新单个属性

  • 在上面的示例中,我基于要更新的​​输入字段(当调用handleChange时)使用开关。我想我可以改为确保所有字段名称都与实体的属性名称同步,并且我可以基于事件中字段的名称(e.target.name)在handleChange中设置实体对象的属性。但是,即使大多数字段仅直接更新实体属性,也很难使每个字段具有单独的需求。我猜想Alternativ是一个具有基于输入名称的默认块设置的开关,对于需要其他更新方式(例如,在实体上对其进行设置之前进行过滤的值)的任何字段,都使用case块。如果您知道通过这种方式处理现场更新的更好方法,请对此发表评论。
  • 更新状态实体

  • 此示例的一个大问题是实体对象的更新方式。由于handleChange中的实体变量已从当前状态设置为实体对象,因此这只是一个指针,更新实体变量将更改对象的状态。 React页面说您永远不要直接更新状态。原因之一是我在调用setState之前以这种方式更新状态时遇到的事情。如果具有shouldComponentUpdate方法,则prevState将包含新状态,因为发送到shouldComponentUpdate的prevState参数的内容基于调用setState时的状态。据我所知,没有简单的方法可以在javascript中克隆对象。所以问题是,当拥有整个对象时,我需要更新(而不是触摸对象中的其他值)的属性,而不是仅运行单个状态变量的setState,那么在不引起这些种类的情况下做到这一点的最佳方法是什么状态混淆?

    最佳答案

  • 任何要更改的内容都会进入State状态。
  • 如果要加载现有实体并对其进行编辑,则需要受控输入,并希望相应地设置值。在大多数情况下(下拉菜单之外),我倾向于远离defaultValue
  • 这与您先前的问题联系在一起。如果指定一个值,则使用的是受控输入,并且必须为任何受控输入提供onChange处理程序,否则将其设置为固定值。受控输入的好处是用户无法编辑它们,因此,如果您锁定了某些属性(出于安全性考虑,可能出于只读目的),那么当用户尝试保存时,即使他们直接编辑了HTML,React也应来自vDOM表示形式的属性值(在这里可能是错误的,但我相信我之前已经对此进行过测试)。无论如何,您必须直接在受控输入上设置onChange。至于使用事件查询(在表单级别),这对于许多事件根本不是一个坏习惯,这只是一个特定的场景(受控输入),您需要为每个元素指定onChange事件。
  • 不能完全确定这个问题是什么,但是我使用了refs而不是target.name。
  • 所以,您是对的,因为您永远不要直接更改状态,这对文档来说是一个棘手的问题。 React将直接更改状态,它将通过setState在实现中进行更改。如果在此方法调用之外更改状态,则会发生意外情况,并会引发错误。

  • shouldComponentUpdate仅做浅层比较,但是这里有一些解决方案。

    一种是对对象进行字符串化处理,这是一种快速而肮脏的对象比较,不建议您这样做,但是可以。

    一个更好的解决方案(我与React + Flux一起使用过)是实现一个propertyChanged bool 型,只需在shouldComponentUpdate中进行检查即可。

    现在,这将需要您知道在事情发生变化时进行设置,即,您已在对象图中更深入地进行了更改。说propertyOne是一个对象,该对象的属性在handleChange方法中被更改。您可以根据需要验证输入,然后将propertyChanged = true设置为,然后需要实现componentDidUpdate 。我们在这里进行假设,但是如果组件已更新,则将propertyChanged设置回false,这样就不会再触发不需要的更新了。我希望这是有道理的。有点像单向notifyPropertyChanged。

    我提供了一个简短的示例,说明我可能会为更动态的实现而做的事情,该实现允许您向对象添加更多属性(此实现中只有较浅的属性,显然您可以编写更可靠的解决方案)。让我知道您是否还有其他问题,或者我没有回答。

    http://jsfiddle.net/rpv9trhh/
    var e = {
        prop1: 'test',
        prop2: 'wee',
        prop3: 'another property',
        propFour: 'Oh yeah!'
    };
    
    var FormComp = React.createClass({
        getInitialState: function(){
            return {
                entity: this.props.entity
            }
        },
        render: function() {
    
            var ent = this.state.entity;
            var that = this;
            var inputs = [];
    
            for(var key in ent){
                inputs.push(<input 
                   key={key} 
                   style={{display:'block'}} 
                   type="text" 
                   ref={key} onChange={that._propertyChanged.bind(null, key)}
                   value={ent[key]} />)
            }
    
            return <form>
                {inputs}
                <input 
                    type="button" 
                    onClick={this._saveChanges} 
                    value="Save Changes" />
            </form>;
        },
        _propertyChanged: function(propName) {
            var nextProp = this.refs[propName].getDOMNode().value;
            var nextEntity = this.state.entity;
            nextEntity[propName] = nextProp;
    
            this.setState({
                entity: nextEntity
            });
        },
        _saveChanges: function() {
            var updatedEntity = this.state.entity;
    
            for(var key in updatedEntity){
                alert(updatedEntity[key]);
            }
    
            //TODO: Call to service to save the entity, i.e.    
            ActionCreators.saveEntity(updatedEntity);
        }
    });
    
    React.renderComponent(<FormComp entity={e} />, document.body);
    

    关于javascript - ReactJS表单组件的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26626454/

    有关javascript - ReactJS表单组件的最佳实践的更多相关文章

    1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    2. ruby-on-rails - Rails 编辑表单不显示嵌套项 - 2

      我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib

    3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

      我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

    4. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

      我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

    5. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

      导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

    6. ruby-on-rails - Rails 中同一个类的多个关联的最佳实践? - 2

      我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来

    7. ruby-on-rails - 向 Rails 3 添加 Ruby 扩展方法的最佳实践? - 2

      我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion

    8. ruby - 最佳原则中的原则 - 2

      我似乎经常遇到一些设计问题,但我不知道是什么是真的很合适。一方面我经常听到我应该限制耦合和坚持单一职责,但当我这样做时,我常常发现它很困难到在需要时将信息获取到程序的一部分。为了例如,classSingerdefinitialize(name)@name=nameendattr:nameend那么Song应该是:classSongdefnew(singer)@singer=singerendend或classSongdefnew(singer_name)@singer_name=singer_nameendend后者耦合性小,按道理应该用。但如果我以后发现宋有什么需要了解更多歌手,我的

    9. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

      我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

    10. ruby-on-rails - 与 ActiveMerchant 一起使用的最佳支付网关是什么? - 2

      我需要使用ActiveMerchant库在我们的一个Rails应用程序中设置支付解决方案。尽管这个问题非常主观,但人们对主要网关(BrainTree、Authorize.net等)的体验如何?它必须:处理定期付款。有能力记入个人帐户。能够取消付款。有办法存储用户的付款详细信息(例如Authotize.netsCIM)。干杯 最佳答案 ActiveMerchant很棒,但在过去一年左右的时间里,我在使用它时发现了一些问题。首先,虽然某些网关可能会得到“支持”——但并非所有功能都包含在内。查看功能矩阵以确保完全支持您选择的网关-http

    随机推荐