У меня есть массив писем (как часть более крупной модели). Они отображаются в отдельных строках с кнопкой удаления для каждого (сам адрес может быть обновлен непосредственно в поле ввода). К сожалению, я не знаю, как сделать это в реакции, когда входные данные отображаются с помощью функции карты. (Я конвертирую проект метеоритного пламени в реакцию метеора).

Все отображается, но как мне прикрепить к событию change, чтобы я мог обновить свой массив писем? Значение onChange + нужно как-то установить.

Это функция карты

return this.data.emailGroup.emails.map((email) => {
            return (
                <div key={email} className="input-group">
                    <input type="text" className="form-control" onChange={self.handleEmailListChange} value={email}/>

                    <div className="input-group-btn">
                        <button type="button"
                                className="btn btn-default remove-email"><span
                            className="glyphicon glyphicon-remove"></span></button>
                    </div>
                </div>
            );
        });

Исходное состояние (которое заполняется данными из базы данных:

 getInitialState() {
      return {
          name : '',
          description: '',
          emails : [],
          newEmailAddress : ''
      }
    },

По запросу здесь используется метод рендеринга (для этого требуется метод getContent. Метод getcontent есть, потому что в метеоре мне нужно ждать данных, поэтому в то же время мне нужно состояние загрузки.

   getContent() {
        return (

            <div className="box box-success">
                <div className="box-header with-border">
                    <h3 className="box-title">List of emails</h3>
                </div>
                <form role="form" className="form-horizontal">
                    <div className="box-body">
                        <p>Below is a list of email addresses which are added to this email group. If
                            you
                            want
                            to add more
                            you can add them one by one by inputting in the box below or add a list into
                            the
                            same box (email
                            addresses have to be seperated by either a space or ;) then press Add to add
                            to
                            the
                            list. You can edit
                            the addresses directly as well as remove them.</p>
                        <div className="input-group">
                            <input type="text" className="form-control"

                                   value={this.state.newEmailAddress}
                                   onChange={this.handleAddNewEmail}
                                   placeholder="Email addresses seperated by a space or a semicolon ; i.e. test1@test.se;test2@test.se"/>
                    <span className="input-group-btn">
                      <button type="button" onClick={this.handleAddNewEmailButton} className="btn btn-info btn-flat add-email">Add</button>
                    </span>
                        </div>
                        <br/>
                        {this.renderEmail()}
                    </div>
                </form>
            </div>
        )
    },
    render()
    {
    var contentStyle = {
        minHeight : '946px'
    };
        return (
            <div className="content-wrapper" style={contentStyle}>
                <section className="content-header">
                    <h1>
                        {this.data.emailGroup? this.data.emailGroup.name : 'hello'}
                    </h1>
                    <small> Created by: Christian Klinton</small>
                    <br/>
                    <small> Last updated by: Christian Klinton - 2015-11-12 08:10:11</small>
                    <ol className="breadcrumb">
                        <li><a href="/emailGroups"><i className="fa fa-dashboard"></i> Home</a></li>
                        <li><a href="/emailGroups">Email groups</a></li>
                        <li className="active">{this.data.emailGroup? this.data.emailGroup.name : 'loading'}</li>
                    </ol>
                </section>
                <section className="content">
                    <div className="row">
                        <div className="col-md-6">
                            <div className="box box-primary">
                                <div className="box-header with-border">
                                    <h3 className="box-title">Information</h3>

                                </div>
                                <form role="form">
                                    <div className="box-body">
                                        <div className="form-group">
                                            <label htmlFor="inputName">Name</label>
                                            <input type="email" className="form-control" id="name"
                                                   onChange={this.handleNameChange}
                                                   placeholder="Set the name of the email group" autoComplete="off"
                                                  value={this.state.name}/>
                                        </div>

                                        <div className="form-group">
                                            <label>Description</label>
                                    <textarea className="form-control" rows="3" id="description"
                                              placeholder="Enter a description what and how the template is used..."
                                              onChange={this.handleDesriptionChange}
                                              value={this.state.description}
                                    ></textarea>
                                        </div>


                                    </div>
                                </form>
                            </div>
                        </div>
                        <div className="col-md-6">
                            {this.data.emailGroup? this.getContent() : <p>Loading</p> }
                        </div>
                        <div className="form-group">
                            <div className="col-sm-offset-8 col-sm-4">
                                <div className="pull-right">
                                    <button className="btn btn-primary">Delete all</button>
                                    <button className="btn btn-primary save">Save</button>
                                </div>
                            </div>
                        </div>
                    </div>
                </section>
            </div>
        )
    }
14
Todilo 16 Дек 2015 в 23:07

3 ответа

Лучший ответ

React требует, чтобы у каждого элемента в отображаемом массиве было что-то уникальное, это называется key и это атрибут.

Если вы не знаете, что назначить ключу, просто назначьте ему индексы массива:

this.props.doors.map((door, index) => (
    <div key={index} className="door"></div>
));

Вот то же решение, примененное к вашей проблеме:

return this.data.emailGroup.emails.map((email, index) => {
    return (
        <div key={index} className="input-group">
            <input type="text"
                   className="form-control"
                   onChange={self.handleEmailListChange.bind(this, index)} value={email}/>
        </div>
    );
});

Обратите внимание, как я связал handleEmailListChange для получения индекса измененного электронного письма. Если handleEmailListChange принимает индекс, он может обновить измененную электронную почту в состоянии:

handleEmailListChange: function(index, event) {
    var emails = this.state.emails.slice(); // Make a copy of the emails first.
    emails[index] = event.target.value; // Update it with the modified email.
    this.setState({emails: emails}); // Update the state.
}
13
Moshe Revah 8 Май 2018 в 20:21

Вы должны поместить свой Array.map прямо в вашу render() функцию. Просто позаботьтесь о том, чтобы каждый элемент массива был внутри родительского элемента (<div> здесь) и должен иметь уникальный key={}

class ArrayMap extends React.Component{
  //your functions
  handleEmailChanged(key){
    // Handle email
  }
  render(){
    return(
      <div>
        {
          this.data.emailGroup.emails.map((email) => {
            <div key={email.key}>
              <button onClick={this.handleEmailChanged.bind(this,email.key)}/>
            </div>
          });
        }
      </div>
    );
  }
}
2
Naisheel Verdhan 16 Дек 2015 в 20:22

Я считаю, что вы ищете что-то вроде этого:

MyPage = React.createClass({
  mixins: [ReactMeteorData],

  getMeteorData() {
    // ...
  },

  render() {
    const emails = this.data.emailGroup.emails.map((email) => {
      return (
        <div key={email} className="input-group">
          <input type="text" className="form-control"
                 onChange={this.handleEmailListChange} value={email} />

          <div className="input-group-btn">
            <button type="button"
                    className="btn btn-default remove-email"><span
              className="glyphicon glyphicon-remove" /></button>
          </div>
        </div>
      );
    });

    return <div>
      {emails}
    </div>
  }
});

Я изменил self на this. Поскольку вы используете функцию стрелки ES6, нет необходимости назначать self = this.

1
ffxsam 16 Дек 2015 в 20:17