kurtgn
kurtgn

Reputation: 8710

mobx: how to observe changes in nested objects?

I have two models: a MessageModel that contains message text (observable), and MessageListModel that contains a list of these MessageModel objects (observable too).

I registered a mobx.autorun() on each change to the message list.

However, autorun triggers on adding/removing messages from list, but not on changing text of existing messages.

Example:

My MessageListModel:


import { observable, decorate } from "mobx";
import MessageModel from "./MessageModel";
import * as mobx from "mobx";

class MessageListModel {

  messages = [];

  constructor() {
        mobx.autorun(() => {
          console.log('Autorun triggered!');
          console.log(this.messages.length);
        });
    }

  addMessage(text) {
    this.messages.push(new MessageModel({ messageList: this, text: text }));
  }

  getMessageText(index) {
    return this.messages[index].text;
  }

  setMessageText(index, messageText) {
    this.messages[index].text = messageText;
  }
}

decorate(MessageListModel, {
  messages: observable,  // don't wanna use decorator syntax
})


export default MessageListModel;

my MessageModel:


import { observable, computed, action, decorate } from "mobx";
import {observer} from "mobx-react";

class MessageModel {

  constructor({messageList, text}) {
    this.text = text;
    this.messageList = messageList;
  }

  text = undefined;
}

decorate(MessageModel, {
  text: observable,
})


export default MessageModel;

Trying to run this:

const messageList = new MessageListModel();

messageList.addMessage('msg1');   // triggers autorun
messageList.addMessage('msg2');   // triggers autorun

messageList.setMessageText(1, 'other text');  // does not trigger autorun
messageList.setMessageText(0, 'other text');  // does not trigger autorun either


how do I make it observe changes to my messages, and not to their amount?

Upvotes: 3

Views: 3241

Answers (1)

Ivan V.
Ivan V.

Reputation: 8081

In your autorun method, you are only listening for changes in the length of the message array so the only thing that is tracked in that autorun function is the length property of the array.

try changing the autorun to this to see the difference:

mobx.autorun(() => {
  console.log('Autorun triggered!');
  console.log(this.messages.length);

  this.messages.map((model)=>{
    console.log(model.text)
  })      
});

In the example above we are accessing the text property on the model so any time you change text on any model, autorun will execute.

So, autorun will only run when properties that are explicitly tracked (accessed inside the function) are changed.

Upvotes: 1

Related Questions