javascript - 如何使用 ReactJS 从动态创建的输入中获取值

标签 javascript forms reactjs ecmascript-6

I have inputs in my page added based on a period of time for example if the period is a week I would have 7 text inputs if the period is two weeks I would have 15 text inputs I already done that it is not the problem now i want to get the values entered in the created text fields knowing that in my render there is only one input that is duplicated a number of times according to the period given

this is how i render my inputs

render() {
    const days = [];
    let day = this.props.StartOfWeek;
    while (day <= this.props.EndOfWeek) {
      days.push(moment(day).format('ddd, DD-MM'));
      day = day.clone().add(1, 'd');
    }
    const daysCode = days.map((displayedDay) => {
    return (
        <td className={this.isWeek(displayedDay)}>
          <tr>{displayedDay}</tr>
          <tr>  <input type="text" key={displayedDay.id} size="3" /></tr>
        </td>);
    });

关于我如何继续的任何想法?

最佳答案

最简单的方法,使用箭头函数:

class InputsList extends React.Component {

    render() {
        const items = this.props.fields.map((field, i) => (
            <YourInputComponent onChange={
                (e) => this.props.onChange(i, e.target.value) } />
        );

        return (<div>{ items }</div>);
    }
} 

这种方法的问题在于 onChange 中的箭头函数将在每次调用 render 时重新分配一个新函数。由于以下原因,这可能会导致性能问题:

  • 纯组件将再次呈现,因为旧(箭头)函数和新(箭头)函数将有所不同,即使两者调用的是完全相同的函数。
  • 用于摆脱那些旧功能的垃圾收集器开销。

更好的方法是将任何相关数据向下传递给 YourInputComponent,它将负责使用相关索引/id 调用 onChange,以便您识别哪个输入触发了事件。

class InputsList extends React.Component {

    render() {
        const items = this.props.fields.map((field, i) => (
            <YourInputComponent index={ i } onChange={ this.props.onChange } />
        );

        return (<div>{ items }</div>);
    }
}

YourInputComponent 中你会有这样的东西:

this.props.onChange(this.props.index, e.target.value);

现在传递给 onChange 的函数将始终相同,只要它在父组件中不发生变化,所以 YourInputComponent 不会重新渲染。

这里有第一种方法的工作示例:

class List extends React.PureComponent {
  render() {
    const { values, length } = this.props;
    const items = [];
    
    for (let i = 0; i < length; ++i) {
      const value = values[i];
      
      items.push(<li key={ `${ value }-${ i }` } className="list__item">{ value }</li>);
    }
    
    return (<ul>{ items }</ul>);
  }
}

class InputsList extends React.PureComponent {

  render() {
    const { name, label, totalInputs, onChange } = this.props;
    const inputs = [];

    for (let i = 0; i < totalInputs; ++i) {
      inputs.push(
        <li key={ i }>
          <label className="inputs__label">
            { `${ label } ${ i + 1 }` }
            
            <input
              className="inputs__input"
              type='text'
              name={ `${ name }-${ i }` } 
              onInput={ (e) => onChange(i, e.target.value) } />
          </label>
        </li>
      );
    }

    return (<ul>{ inputs }</ul>);
  }
}

class RadioTabs extends React.PureComponent {

  render() {   
    const { name, value, options, onChange } = this.props;
  
    const radios = options.map(option => (
      <li key={ option }>
        <label className="radioTabs__label">
          <input
            className="radioTabs__input"
            type="radio"
            value={ option }
            checked={ value === option }
            name={ name }
            onChange={ onChange } />
            
            <span className="radioTabs__text">{ option }</span>
        </label>
      </li>
    ));
  
    return(
      <ul className="radioTabs__base">
        { radios }
      </ul>
    );
  }
}

class App extends React.Component {

  static options = [1, 2, 3, 4, 5, 6, 7];

  constructor(props) {
    super(props);
    
    this.state = {
      totalInputs: App.options[0],
      values: [],
    };
  }
  
  onTotalInputsChange = (e) => {    
    this.setState({
      totalInputs: parseInt(e.target.value),
      values: this.state.values,
    });
  };
  
  onInputsChange = (index, value) => {
    const values = [ ...this.state.values ];
    
    values[index] = value;
    
    this.setState({
      totalInputs: this.state.totalInputs,
      values,
    });
  };
  
  render() {
  
    const { totalInputs, values }  = this.state;
  
    return(
      <div className="app">
        <div className="header">
          <RadioTabs
            name="days"
            value={ totalInputs }
            options={ App.options }
            onChange={ this.onTotalInputsChange } />
        </div>

        <div className="columns">
          <div className="left">
            <InputsList
              name="values"
              totalInputs={ totalInputs }
              label="Day"
              onChange={ this.onInputsChange } />
          </div>

          <div className="right">
            <List values={ values } length={ totalInputs }/>
          </div>
        </div>
      </div>
    );
  }
}


ReactDOM.render(<App />, document.getElementById('app'));
body {
  font-family: monospace;
  margin: 0;
}

ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.app {
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.header {
  padding: 4px;
  border-bottom: 2px solid black;
  flex: 0 0 auto;
}

.columns {
  display: flex;
  flex: 1 1 auto;
}

.left,
.right {
  flex: 1 0 0;
  overflow-y: scroll;
  padding: 4px;
}

.left {
  border-right: 2px solid black;
}

/* RADIO TABS */

.radioTabs__base {
  display: flex;
  align-items: center;
}
.radioTabs__label {
  display: block;
  padding: 4px 0;
  cursor: pointer;
  border-radius: 2px;
  min-height: 27px;
  min-width: 35px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.radioTabs__label:hover {
  background: #EEE;
}

.radioTabs__input {
  display: none;
}

.radioTabs__text {
  display: block;
  padding: 2px 4px 0;
  border-bottom: 2px solid transparent;
}

.radioTabs__input:checked + .radioTabs__text {
  border-bottom-color: black;
}

/* INPUTS LIST */

.inputs__label {
  display: block;
  padding: 4px 8px;
  cursor: pointer;
  border-radius: 2px;
  display: flex;
  align-items: center;
}

.inputs__label:hover {
  background: #EEE;
}

.inputs__input {
  border: 2px solid black;
  padding: 4px 8px;
  margin: 0 0 0 8px;
  font-family: monospace;
  flex: 1 0 auto;
}

/* LIST */

.list__item {
  border-bottom: 2px solid black;
  line-height: 33px;
  height: 33px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
<div id="app"></div>

<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

关于javascript - 如何使用 ReactJS 从动态创建的输入中获取值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50518469/

相关文章:

javascript - 数据保存到 DB 后对 DIV 进行永久更改

javascript - 如何从 AngularJS 上隐藏的 ng-show false 元素获取某些属性(高度)

php - 我的 PHP 联系表无法发送

reactjs - 使用 redux 从不相关的组件传递状态?

javascript - 渲染 react 组件预览

javascript - 选择不同单选按钮时如何更改段落内容

javascript - 从外部函数调用 Image.getSize

php - 将表单提交到页面并根据输入显示不同的 div

java - 在 Java 中提交表单后加载新页面

reactjs - Redux connect 的 mapStateToProps 的正确类型声明 (TypeScript 2)