Реакция: удаление динамического ввода из состояния, повторный ввод

#javascript #arrays #reactjs #state #slice

#javascript #массивы #reactjs #состояние #срез

Вопрос:

У меня возникли проблемы с отладкой этой ситуации. Я пытаюсь удалить индекс из массива, предоставленного API. Я сохраняю это в родительском состоянии после проверки изменения реквизита его родителем. Здесь все хорошо. Я могу сохранить любые изменения реквизита в состоянии родительской формы.

Родительская форма отображает все в TemplateData, и я определяю, какой это тип, а затем визуализирую компонент в зависимости.

Кнопка удаления всегда будет находиться только в DynamicInputGroup, поэтому я передаю эту функцию через props. В DynamicInputGroup мне нужно сопоставить массив, переданный от родительского элемента, затем сопоставить объекты внутри этого массива для отображения каждого отдельного ввода. Снова использование реквизитов, переданных вниз, чтобы определить, какой ввод отображать, такой же, как родительский.

Вот где все идет не так. Когда я нажимаю удалить, скажем, индекс 2 из 5, я вижу, что индекс удаляется в состоянии, но отображается то, что удаляется индекс 5.Я не уверен, как это сделать. Я провел исследование и прочитал, что ключи вступают в игру? Я попытался установить переменную в функции рендеринга в состояние, чтобы она обновлялась, но ничего. последний индекс всегда удаляется. Halp!

Родительская форма

 this.state = {
    templateData: []
}

removeGroupItem = (index, inputName ) => {
    let group = `${inputName}__group`
    const newState = this.state;
    if (index === -1) return;
    newState.templateData[group].splice(index, 1);
    console.log(newState) // THIS SHOWS CORRECT STATE
    this.setState(newState);
}

render() {
    return (
      {Object.keys(this.state.templateData).map((name, key) => {
          let data = { // SETTING inputType TO DISPLAY CORRECT COMPONENT }
          return (
              <Fragment key={key}>
                  {data.inputType == 'input' amp;amp; <DynamicTextInput {...data} />}
                  {data.inputType == 'rtf' amp;amp; <DynamicRTF {...data}  />}
                  {data.inputType == 'img' amp;amp; <DynamicImageUpload {...data} />}
                  {data.inputType == 'group' amp;amp; <DynamicInputGroup {...data} removeGroupItem={this.removeGroupItem} />} // COMPONENT THAT HOLDS REMOVE BUTTON
              </Fragment>
          )
      })}
    )
}
  

DynamicInputGroup Componenet

 this.state = {
    value: []
}


componentDidMount() {
    this.setState({ value: this.props.value })
}

componentDidUpdate(prevProps) {
    if (this.props.value !== prevProps.value) {
        this.setState({
            value: this.props.value
        })
    }
}

render() {
    return (
        <Fragment>
            <Typography>{this.props.inputName}</Typography>
            {this.state.value.map((value, key) => {
                return (
                    <span>
                    {Object.keys(value).map((input, index) => {
                        let data = { // SETTING inputType TO DISPLAY CORRECT COMPONENT }
                        return (
                            <Grid key={index}>
                                {data.inputType == 'input' amp;amp; <DynamicTextInput {...data} />}
                                {data.inputType == 'rtf' amp;amp; <DynamicRTF {...data} />}
                                {data.inputType == 'img' amp;amp; <DynamicImageUpload {...data} />}
                                {data.inputType == 'group' amp;amp; <DynamicInputGroup {...data} />}
                            </Grid>
                        )
                    })}
                        {key >= 1 ? <span onClick={() => this.props.removeGroupItem(key, this.props.inputName)}>remove</span> : ''}
                    </span>
                )
            })}
        </Fragment>
    )
}
  

Затем, если необходимо, DynamicTextInput

 const DynamicTextInput = (props) => {
    return (
        <Grid>
            <TextField
                name={props.inputName} label={props.inputName} defaultValue={props.value}
                size="small" variant="outlined" fullWidth multiline
            />
        </Grid>
    )
}
  

Ответ №1:

Использование индекса в качестве ключа компонента — плохая практика, особенно если это список, который меняется. Ключ должен быть уникальным идентификатором компонента.

Если у вас нет уникального идентификатора для ваших элементов управления, вы можете создать его на основе метки времени, своего рода uuid, который вы будете хранить в своем состоянии и который всегда будет ссылаться только на один элемент управления.

Представьте, что у вас есть ситуация, когда у вас есть 1 элемент ввода, который имеет значение TextInput 1 . Затем вы добавляете другой ввод из него, и он наследует свой ключ. Теперь у вас нарушен shadow DOM, поскольку вы ссылаетесь на новый ввод вместо старого, потому что ввод с ключом ={0} имеет значение TextInput 1 , но это не то, что вы ожидаете, потому что вы хотите ссылаться на другой ввод.

Комментарии:

1. Пытаюсь придумать уникальный идентификатор для их предоставления. Я думал о значении объекта, но может быть экземпляр неуникальных значений

2. @Ryan uuid — это путь. Вы можете присвоить ему ключ input-${Date.now()} , а затем просто придерживаться этого ключа на протяжении всего сеанса. Если вам нужно, чтобы этот макет / логика сохранялись, вы также должны сохранить этот uuid в своей базе данных.

3. И я бы установил этот ключ для сетки в DynamicInputGroup? Вот где я запутался

4. Да, 1-й дочерний элемент в функции map, в вашем текущем случае это Grid. Дочерние элементы Grid не будут иметь путаницы на этапе согласования

5. Кажется, перемещение кнопки удаления на правильную карту также решает проблему. Но переименование моих ключей в уникальные идентификаторы сработало

Ответ №2:

В этой строке проблема:

 <Fragment key={key}>
  

Поскольку вы используете индекс массива для их отображения Fragments , время согласования завершается неудачно length , и «последний элемент» удаляется. Я бы очень рекомендовал посмотреть это видео, оно такое полезное. Вы должны использовать уникальный идентификатор.