ReactJS mobx - не обновляет наблюдаемый массив

Если в вашем магазине есть список observable:

@obserable public Claimslist: IClaim[] = [];

где IClaim — интерфейс, claims — массив IClaim объектов

IClaim содержит переменную в своем объекте с именем moveOutDate Каждый объект претензии имеет id переменную.

И теперь вы хотите обновить или получить эту переменную по claim id

Итак, у вас есть 2 функции:

Получать

  /**
   * Gets the moveOutDate of a claim by claim ID
   */
  @action getMoveOutDateById = (id: string) => {
    // Get the claim by id
    const claim = this.Claimslist.find((element: IClaim) => element.id === sessionStorage.getItem('claim-id'));
    if (claim) {
      if (!claim.moveOutDate) {
        return undefined;
      }
      return moment(new Date(claim.moveOutDate)).toDate();
    }

    return undefined;
  }

Задавать

  /**
   * Sets moveOutDate in claim by claim ID
   */
  @action public setMoveOutDate = (id: string, date: Date) => {
    const claim = this.Claimslist.find((element: IClaim) => element.id === id);
    if (claim) {
      claim.moveOutDate = date.toString();
    }
  }

Хорошо, но теперь, когда вы сначала используете getMoveOutDateById в своем render, он работает и отображает дату, но как только вы вызываете setMoveOutDateonUpdate компонента даты, рендеринг не будет обновляться, но хранилище будет обновляться, и вы сможете увидеть изменения, только если вы обновляете страницу.

Теперь мне удалось решить эту проблему, выполнив:

this.Claimslist = this.Claimslist.slice();

и добавление скрытого ввода Claimslist:

const {Claimslist} = this.props.claimsStore;

а также

<input type = "hidden" value = {Claimslist} />

Почему это происходит, если весь объект obserable и обернут @action, почему он не меняется без использования slice() и наличия скрытого ввода?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
3 137
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Mobx observable наблюдает только мелкие значения. Это означает, что у меня есть @observable claims[], тогда claims[0] = something вызовет обновление, но claims[0].foo = bar не будет (документы). Чтобы исправить это, вам нужно сделать foo также наблюдаемым, добавив @observable foo к claim объекту.

Рассмотрим следующий пример. Обратите внимание на разницу между Claim1 и Claim2. Компоненты точно такие же, но ClaimView2 будут обновляться, а ClaimView1 — нет. Демо

import React from "react";
import { render } from "react-dom";
import { observable, action } from "mobx";
import { observer } from "mobx-react";

class Claim1 {
  moveOutDate: Date;
  constructor() {
    this.moveOutDate = new Date();
  }
}

@observer
class ClaimsView1 extends React.Component {
  @observable claims: Claim1[] = [
    new Claim1(),
    new Claim1()
  ];

  @action.bound
  updateClaims(){
    this.claims.forEach(claim => {
      claim.moveOutDate = new Date();
    })
  }

  render() {
    return <div>
      <pre>
        {"ClaimsView1 = \n" + JSON.stringify(this.claims, null, "  ")}
      </pre>
      <button onClick = {this.updateClaims}> Update </button>
    </div>
  }
}


class Claim2 {
  @observable moveOutDate: Date;
  constructor() {
    this.moveOutDate = new Date();
  }
}

@observer
class ClaimsView2 extends React.Component {
  @observable claims: Claim2[] = [
    new Claim2(),
    new Claim2()
  ];

  @action.bound
  updateClaims(){
    this.claims.forEach(claim => {
      claim.moveOutDate = new Date();
    })
  }

  render() {
    return <div>
      <pre>
        {"ClaimsView2 = \n" + JSON.stringify(this.claims, null, "  ")}
      </pre>
      <button onClick = {this.updateClaims}> Update </button>
    </div>
  }
}

render(
  <>
    <ClaimsView1 />
    <ClaimsView2 />
  </>,
  document.getElementById("root")
);


Обновлять:

Вот демо для решения, которое я дал в комментариях.

import React from "react";
import { render } from "react-dom";
import { observable, action } from "mobx";
import { observer } from "mobx-react";

interface IClaim {
  moveOutDate: Date;
}

@observer
class ClaimsView extends React.Component<{claims: IClaim[]}> {
  @observable claims: IClaim[] = this.props.claims.map(claim => observable(claim))

  updateClaims = () => {
    this.claims.forEach(claim => {
      claim.moveOutDate = new Date();
    })
  }

  render() {
    return <div>
      <pre>
        {"claims = \n" + JSON.stringify(this.claims, null, "  ")}
      </pre>
      <button onClick = {this.updateClaims}> Update </button>
    </div>
  }
}


render(
  <ClaimsView claims = {[
    { moveOutDate: new Date() },
    { moveOutDate: new Date() }
  ]} />,
  document.getElementById("root")
);

Но IClaim — это интерфейс, и вы не можете сделать это в интерфейсе?

Ben Beri 20.03.2019 23:21

@Ben Вы по-прежнему можете сделать каждое свойство наблюдаемым, передав объект интерфейса IClaim наблюдаемому декоратору/функции, а затем поместив его в массив. документы

Devansh J 20.03.2019 23:31

@Ben и ofc, если у вас уже есть заполненный массив, вы можете сопоставить его с помощью функции observable и переназначить массив.

Devansh J 20.03.2019 23:39

@Ben Я обновил ответ демонстрацией реализации решения в случае интерфейсов. Пожалуйста, проверьте это.

Devansh J 21.03.2019 12:07

Привет спасибо! Но вы должны понимать, что я использую интерфейс с необязательными свойствами, например, переменная?: строка; так что вы не можете сделать это, я думаю

Ben Beri 21.03.2019 12:09

@ Бен, почему ты думаешь, что не можешь этого сделать? замените interface IClaim { moveOutDate: Date } на interface IClaim { moveOutDate: Date, foo?: string } и все равно будет работать. Также Добро пожаловать!

Devansh J 21.03.2019 12:10

но можете ли вы сделать это и для необязательных переменных?

Ben Beri 21.03.2019 12:14

@ Бен Да. Вот демо. Я думаю, это то, что вы хотели, верно?

Devansh J 21.03.2019 12:15

Давайте продолжить обсуждение в чате.

Ben Beri 21.03.2019 13:41

Это не совсем то же самое, отсутствует @observable, это будет то же самое, если:

class Claim1 {
  @observable moveOutDate: Date;
...

Другие вопросы по теме