Вычислено не реактивно?

Я написал этот код, чтобы получить список навыков. Если у пользователя уже есть определенный навык, элемент списка должен быть обновлен до active = false.

Это мой исходный код:

 setup () {

        const user = ref ({
            id: null,
            skills: []
        });

        const available_skills = ref ([
            {value: 'css', label: 'CSS', active: true},
            {value: 'html', label: 'HTML', active: true},
            {value: 'php', label: 'PHP', active: true},
            {value: 'python', label: 'Python', active: true},
            {value: 'sql', label: 'SQL', active: true},
        ]);
 
        const computed_skills = computed (() => {
            let result = available_skills.value.map ((skill) => {
                if (user.value.skills.map ((sk) => {
                    return sk.name;
                }).includes (skill.label)) {
                    skill.active = false;
                }

                return skill;
            });

            return result;
        })


        return {
            user, computed_skills
        }
    },

Это отлично работает при первоначальном рендеринге. Но если я удаляю навык у пользователя, выполняющего
user.skills.splice(index, 1), computed_skills не обновляются.

Почему так?


person SPQRInc    schedule 17.02.2021    source источник
comment
Может быть, попытаться избежать метода сращивания и просто использовать Array.filter? например: user.skills = user.skills.filter((skill) => {/* filter logic here */});   -  person Asimple    schedule 17.02.2021
comment
Мне нужно соединить элемент, если я хочу удалить навык из списка навыков пользователя, так как эти элементы будут сохранены в базе данных.   -  person SPQRInc    schedule 17.02.2021
comment
Я понял этот случай, но склейку можно сделать с помощью Array.filter. Вы переназначите его, и вычисление будет запущено.   -  person Asimple    schedule 17.02.2021


Ответы (3)


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

Предполагая, что user.skills содержит полный набор навыков из available_skills, первое вычисление устанавливает для всех skill.active значение false. Когда пользователь щелкает навык, чтобы удалить его, повторное вычисление не устанавливает снова skill.active (нет предложения else).

let result = available_skills.value.map((skill) => {
   if (
     user.value.skills
       .map((sk) => {
         return sk.name;
       })
       .includes(skill.label)
   ) {
     skill.active = false;
   }
   // ❌ no else to set `skill.active`

   return skill;
});

Однако у вашей вычисленной опоры есть побочный эффект изменения исходных данных (например, в skill.active = false), который следует избегать. Приведенное выше сопоставление должно клонировать исходный элемент skill и вставить новое свойство active:

const skills = user.value.skills.map(sk => sk.name);

let result = available_skills.value.map((skill) => {
  return {
    ...skill,
    active: skills.includes(skill.label)
  }
});

демонстрация

person tony19    schedule 18.02.2021

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

Решение: попробуйте переназначить пользователя, затеняя переменную.

person KaranV    schedule 17.02.2021

slice просто возвращает копию измененного массива, он не меняет исходный экземпляр ... следовательно, вычисляемое свойство не является реактивным

Попробуйте использовать приведенный ниже код

user.skills = user.skills.splice(index, 1);
person shalini    schedule 17.02.2021