Как создать уникальные поля редактирования для определенного элемента в React

Из самого названия. Я изучаю новое в React, и у меня проблема с полями редактирования.

Всякий раз, когда я нажимаю на определенный элемент для редактирования, остальные невыбранные элементы также будут редактироваться, как показано на скриншоте ниже. Мне было интересно, как я могу создать уникальные поля редактирования полей, которые будут редактировать только конкретное поле, выбранное в данный момент. Каждый раз, когда я ввожу новый элемент в editedField, я получаю такую ​​​​ошибку.

Как создать уникальные поля редактирования для определенного элемента в React

Код

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class Skills extends Component {
    constructor(props) {
        super(props);

        this.state = { 
            skills : ["Frost Bolt", "Arcane Missle"],
            skillField : '',
            skiller : '',
            editIsHidden : true,
            editConfIsHidden : true,
            editSkillField : '',
        };

        // Event Listeners
        this.addSkill = this.addSkill.bind(this);
        this.removeSkill = this.removeSkill.bind(this);
        this.editSkill = this.editSkill.bind(this);
        this.handleChangeEvent = this.handleChangeEvent.bind(this);
        this.clearField = this.clearField.bind(this);
        this.confirmEdit = this.confirmEdit.bind(this);
    }

    clearField() {
        this.setState({
            skillField : ''
        });
    }

    handleChangeEvent(event, element) {
        this.setState({
            [element] : event.target.value
        });
    }

    editSkill(editedSkill) {

        this.setState({
            editIsHidden : false
        });

        this.setState({
            editConfIsHidden : false
        });
    }

    confirmEdit(oldEditedSkill) {
        let index = 0;
        let skillsArray = this.state.skills;
        let newEditedSkill = this.state.editSkillField;

        this.state.skills.forEach(function(skill) {
            if (skill == oldEditedSkill) {
                skillsArray[index] = newEditedSkill;
                console.info(newEditedSkill);
            }
            index++;
        });

        this.setState({
            skills : skillsArray
        });

        this.setState({
            editConfIsHidden : true
        });

        this.setState({
            editIsHidden : true
        });

        console.info(this.state.skills);
    }

    addSkill() {
        this.state.skills.push(this.state.skillField);
        this.setState({
            skills: this.state.skills
        });
        console.info(this.state.skills);
        this.clearField();
    }

    removeSkill(removedSkill) {
        let adr = 0;
        let skillsArray = this.state.skills;

        this.state.skills.forEach(function(skill) {
            if (skill == removedSkill) {
                skillsArray.splice(adr, 1); 
            }
            adr++;
        });

        this.setState({
            skills : skillsArray
        });
    }

    render() {
        const skillLists = this.state.skills.map((val) => {
            return  <li>{val}
                        <input onChange = {(e) => this.handleChangeEvent(e, "editSkillField")} value = {this.state.editSkillField} className = {this.state.editIsHidden ? 'hidden' : ''} />
                        <button onClick = {() => this.removeSkill(val)}>x</button>
                        <button onClick = {() => this.editSkill(val)}>e</button>
                        <button onClick = {() => this.confirmEdit(val)} className = {this.state.editConfIsHidden ? 'hidden' : ''} >ok</button>
                    </li>
        });
        return (
            <div>
                <input onChange = {(e) => this.handleChangeEvent(e, "skillField")} value = {this.state.skillField} />
                <button onClick = {this.addSkill}>Add Skill</button>
                <h4>Skills</h4>
                <ul>{skillLists}</ul>
            </div>
        );
    }
}

export default Skills;

🤔 А знаете ли вы, что...
React предлагает виртуальное DOM для оптимизации производительности при обновлении интерфейса.


1
188
2

Ответы:

Вам следует подумать о том, чтобы изменить его на такой объект, чтобы вы могли легко справиться с этим, и вам не нужно поддерживать другие свойства.

skills: [{ id: "Frost Bolt", value: '' }, { id: "Arcane Missle", value: '' }],

при изменении ввода попробуйте изменить так

  handleChangeEventSkills(event, element) {
    this.setState({
      skills: this.state.skills.map(a => {
        if (a.id === element) {
          a.value = event.target.Value;
        }
        return a;
      })
    });
  }

оставьте свой хендлмен как есть

  handleChangeEvent(event, element) {
    this.setState({
      [element]:event.target.value
    });
  }

и назовите это во входных данных навыков, как это

 <input onChange = {(e) => this.handleChangeEventSkills(e, val.id)} 
value = {val.val} className = {this.state.editIsHidden ? 'hidden' : ''} />

Вот демо


Решено

Если вы внимательно посмотрите на код, в котором отображаются skills, можно обнаружить, что имя класса hidden включено или отключено для каждого элемента в списке, как в приведенном ниже коде.

<input onChange = {(e) => this.handleChangeEvent(e, "editSkillField")} value= {this.state.editSkillField} className = {this.state.editIsHidden ? 'hidden' : ''} />

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

Ваша функция editSkill должна хранить skill, который необходимо отредактировать. Что-то ниже будет работать.

editSkill(editedSkill) {
 this.setState({
  editIsHidden : editedSkill
 });

 this.setState({
  editConfIsHidden : editedSkill
 });
}

Затем ваш рендер немного изменится, как показано ниже.

const skillLists = this.state.skills.map((val) => {
 return  <li>{val}
          <input onChange = {(e) => this.handleChangeEvent(e, "editSkillField")} value = {this.state.editSkillField} className = {(this.state.editIsHidden !== val) ? 'hidden' : ''} />
          <button onClick = {() => this.removeSkill(val)}>x</button>
          <button onClick = {() => this.editSkill(val)}>e</button>
          <button onClick = {() => this.confirmEdit(val)} className = {(this.state.editConfIsHidden !== val) ? 'hidden' : ''} >ok</button>
         </li>
});

Затем в вашей функции confirmEdit сбросьте значения соответствующих переменных состояния, например

 this.setState({
  editConfIsHidden : null,
 });

 this.setState({
  editIsHidden : null,
 });

Это поможет вашему решению. Тем не менее, есть несколько вещей, которые следует учитывать.

  1. Старайтесь поддерживать меньшее количество состояний. Я надеюсь, что состояния editConfIsHidden и editIsHidden можно будет заменить одним состоянием, если только у вас нет особых случаев использования их по отдельности.

  2. Когда мы пытаемся установить состояние, мы можем использовать один вызов this.setState вместо последовательного и многократного вызова setState, как показано в этом ответе.