包装组件意味着它不再关注重新渲染

时间:2016-11-28 19:30:38

标签: javascript reactjs

我有很长的反应。以前,它有一堆定义如下的组件:

<input
  type='text'
  value={this.state.form.nameOfFormField}
  onChange={this.updateForm('nameOfFormField')} />

其中updateForm(field) => (e) => {}形式的函数,可以更轻松地重用代码。

我想让这更容易维护,所以我创建了一个组件SpecialInput,其定义如下:

const SpecialInputBuilder = (form, onChange) => ({ field, ..props }) => (
  <input
    type='text'
    value={form[field]}
    onChange={onChange(field)}
    {...props} />
)

现在,我可以在渲染过程中定义输入,如下所示:

const SpecialInput = SpecialInputBuilder(this.state.form, this.updateForm)

并在像这样的组件中使用它:

<SpecialInput field='nameOfFormField' />

显然,这更加简洁。但这也意味着每次输入字段时输入字段都会丢失焦点(即调用updateForm时),因为每次SpecialInput函数都定义render时调用。为每个元素定义key似乎根本不能解决问题。如何在使用这个更简单的组件时解决这个问题?有中间立场吗?

3 个答案:

答案 0 :(得分:1)

为什么不将输入构建器更改为反应组件?

const SpecialInput = (props) => {
  return (
    <input
      value={props.form[props.field]}
      {...props}
      type={props.type || 'text'}
      onChange={() => props.onChange(props.field)} 
    />
  )
}

并以同样的方式使用它。

<SpecialInput field='nameOfFormField' onChange={this.updateForm} form={this.state.form} />

答案 1 :(得分:0)

主要问题是,onChange调用在呈现时立即执行,而不是在输入更改时调用要调用的函数。

// this executes immediately
onChange={onChange(field)}

// this is a reference to the function with a prop prepended
onChange={onChange.bind(this,field)}

答案 2 :(得分:0)

我有一个类似的方法,但最终改为此;

(1)输入typer子组件:

import React, { Component } from 'react';

class FreeTextField extends Component {
  inputValueFn(e) {
    this.props.userInput(this.props.responseObject, e.target.value);
  }
  render() {
    return (
      <div className="input-group">
            <label>{this.props.buttonText ? this.props.buttonText : "Firstname"}</label>
            <input type={this.props.type} placeholder="" className="form-control" defaultValue={this.props.defaultValue} onChange={this.inputValueFn.bind(this)} />
      </div>
    );
  }
}

export default FreeTextField;

(2)从父组件中,您可以通过道具指定所有相关儿童attr

// import
import FreeTextField from './pathTo/FreeTextField';

// Initial state
this.state = {
responseObject: {}
}

// onChange it updates the responseObject
    userInput(fieldKey,value) {
        let responseObject = this.state.responseObject;
        responseObject[fieldKey] = value;
        this.setState({responseObject:responseObject});
    }

// component render()
<FreeTextField 
buttonText="First Name" 
type="text" 
formObjectKey="first_name" 
userInput{this.userInput.bind(this)} />