构建 react 中可重用灵活的表单组件

本文探讨了在React中构建表单组件的两种方式:受控组件和非受控组件。受控组件的状态由父组件管理,而非受控组件则不维护内部状态,常用于数据展示。在处理多个受控组件时,文章提到了状态管理的挑战以及如何通过优化避免不必要的函数创建,如利用React context和HOC(高阶组件)来提升性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

组件

受控组件与非受控组件

非受控即 组件内部不存在状态,组件的状态由父组件传入;一般该类型组件用来做数据展示,但不可控制

非受控组件通常我们会写成纯函数想这样:

import React from 'react'

export default function UncontrollForm({user}){
    return(
        <div className="profile-form">
            <div className="field">
                <label>Name</label>
                <input type="text"
                 readOnly
                 value={user.name}
                 />
            </div>
        </div>
    )
}

受控组件

该类型组件,接受父组件传入的数据后,若自身数据更新将数据传递给父组件并更新自身状态
我们一般会这样做:

import React from 'react'
export default class ArrowFncForm extends React.PureComponent{
    constructor(props){
        super(props);
        this.handleChange=this.handleChange.bind(this);
    }
    handleChange(type,value){
        //处理业务逻辑
        console.log(type,'--------',value)
      //传递给父组件
      this.props.onChange(type,value);
    }
    render(){
        const {user}=this.props;
        return(
            <div className="profile-form">
                <div className="field">
                    <label>Name</label>
                    <input type="text"
                     value={user.name}
                     onChange={e=>this.handleChange('name',e.target.value)}
                     />
                </div>
                <div className="field">
                    <label>E-mail</label>
                    <input type="text"
                     value={user.email}
                     onChange={e=>this.handleChange('email',e.target.value)}
                     />
                </div>
            </div>
        )
    }
}

问题: 当多个受控组件时,我们会给处理函数加入type字段来区分,在onChange中要给函数传递参数我们只能用箭头函数包一层,即向上面那样…
但这样做也会导致 render 每次创建/替换箭头函数,接受这些函数的 内容也将重新呈现。

我们会这样修正:

import React from 'react'
export default class ArrowFncForm extends React.PureComponent{
    constructor(props){
        super(props);
        this.handleNameChange=this.handleNameChange.bind(this);
        this.handleEmailChange=this.handleEmailChange.bind(this);
    }
    handleNameChange(e){
      //传递给父组件
      this.props.onChange('name',e.target.value);
    }
    handleEmailChange(e){
        //传递给父组件
        this.props.onChange('email',e.target.value);
      }
    render(){
        const {user}=this.props;
        return(
            <div className="profile-form">
                <div className="field">
                    <label>Name</label>
                    <input type="text"
                     value={user.name}
                     onChange={this.handleNameChange}
                     />
                </div>
                <div className="field">
                    <label>E-mail</label>
                    <input type="text"
                     value={user.email}
                     onChange={this.handleEmailChange}
                     />
                </div>
            </div>
        )
    }
}

提示:有人可能会给 input 加上name属性,此时在处理函数中获取,这样会减少一些代码但本质和上面一样。该做法不在次讲述

优化form

原文传送
我们可以通过React context来将公用的事件进行传输,然后将输入组件包裹在HOC(高级组件)中以读取上下文。
示例如下:

// EntityData.jsx
const EntityDataContext = React.createContext();
export function withEntityData(Component) {
  return function EntityDataComponent(props) {
    return (
      <EntityDataContext.Consumer>
        { entityProps => {
          const source = props.source || entityProps.source;
          const path = props.path;
          const sourceValue = _.get(path, source);
          const value = props.value !== undefined ?
            props.value : sourceValue;
          const onChange = props.onChange || entityProps.onChange;
          return (
            <Component
              { ...props }
              source={ source }
              path={ path}
              value={ value } />
              onChange={ onChange } />
          );
        }}
      </EntityDataContext.Consumer>
    );
  };
}
export default class EntityData extends React.PureComponent {
  render() {
    return (
      <EntityDataContext.Provider value={{
        source: this.props.source,
        onChange: this.props.onChange
      }}>
        { this.props.children }
      </EntityDataContext.Provider>
    );
  }
}
//  StringInput.jsx
import React from 'react'
import {withEntityData} from '../EntityData'
 class StringInput extends React.PureComponent{
    constructor(props){
        super(props);
        this.handleChange=this.handleChange.bind(this);
    }
    handleChange(e){
        this.props.onChange && this.props.onChange(e.target.value);
    }
    render(){
        const {value}=this.props;
        return(
            <input
                type='text'
                value={value}
                onChange={this.handleChange}
            ></input>
        )
    }
}
export default withEntityData(StringInput)

现在我们可以这样使用:

//ProfileForm.jsx
class ProfileForm extends React.PureComponent {
  render() {
    const { user, onChange } = this.props;
    
    return (
      <div className="profile-form">
        <EntityData source={ user } onChange={ onChange }>
          <StringField label="Name" path="name" />
          <StringField label="E-mail" path="email" />
          <StringField label="Phone" path="phone" />
        </EntityData>
      </div>
    );
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值