3

Simple: the computed value isn't updating when the observable it references changes.

import {observable,computed,action} from 'mobx';

export default class anObject {

    // THESE WRITTEN CHARACTERISTICS ARE MANDATORY
    @observable attributes = {}; // {attribute : [values]}
    @observable attributeOrder = {}; // {attribute: order-index}
    @observable attributeToggle = {}; // {attribute : bool}


    @computed get orderedAttributeKeys() {
        const orderedAttributeKeys = [];

        Object.entries(this.attributeOrder).forEach(
            ([attrName, index]) => orderedAttributeKeys[index] = attrName
        );

        return orderedAttributeKeys;
    };

    changeAttribute = (existingAttr, newAttr) => {
        this.attributes[newAttr] = this.attributes[existingAttr].slice(0);
        delete this.attributes[existingAttr];

        this.attributeOrder[newAttr] = this.attributeOrder[existingAttr];
        delete this.attributeOrder[existingAttr];

        this.attributeToggle[newAttr] = this.attributeToggle[existingAttr];
        delete this.attributeToggle[existingAttr];

        console.log(this.orderedAttributeKeys)
    };

}

After calling changeAttribute, this.orderedAttributeKeys does not return a new value. The node appears unchanged.

However, if I remove the @computed and make it a normal (non-getter) function, then for some reason this.orderedAttributeKeys does display the new values. Why is this?

EDIT: ADDED MORE INFORMATION

It updates judging by logs and debugging tools, but doesn't render on the screen (the below component has this code, but does NOT re-render). Why?

{/* ATTRIBUTES */}
<div>
    <h5>Attributes</h5>
    {
    this.props.appStore.repo.canvas.pointerToObjectAboveInCanvas.orderedAttributeKeys.map((attr) => { return <Attribute node={node} attribute={attr} key={attr}/>})
    }
</div>

pointerToObjectAboveInCanvas is a variable. It's been set to point to the object above.

The changeAttribute function in anObject is called in this pattern. It starts in the Attribute component with this method

    handleAttrKeyChange = async (existingKey, newKey) => {
        await this.canvas.updateNodeAttrKey(this.props.node, existingKey, newKey);
        this.setState({attributeEdit: false}); // The Attribute component re-renders (we change from an Input holding the attribute prop, to a div. But the above component which calls Attribute doesn't re-render, so the attribute prop is the same
    };

which calls this method in another object (this.canvas)

    updateNodeAttrKey = (node, existingKey, newKey) => {
        if (existingKey === newKey) { return { success: true } }
        else if (newKey === "") { return { success: false, errors: [{msg: "If you'd like to delete this attribute, click on the red cross to the right!"}] } }

        node.changeAttribute(existingKey, newKey);

        return { success: true }
    };

Why isn't the component that holds Attribute re-rendering? It's calling orderedAttributeKeys!!! Or am I asking the wrong question, and something else is the issue...

An interesting fact is this same set of calls happens for changing the attributeValue (attribute is the key in anObject's observable dictionary, attributeValue is the value), BUT it shows up (because the Attribute component re-renders and it pulls directly from the node's attribute dictionary to extract the values. Again, this is the issue, an attribute key changes but the component outside it doesn't re-render so the attribute prop doesn't change?!!!

ali_wetrill
  • 173
  • 1
  • 9

2 Answers2

0

It is because you have decorated changeAttribute with the @action decorator.

This means that all observable mutations within that function occur in a single transaction - e.g. after the console log.

If you remove the @action decorator you should see that those observables get updated on the line they are called and your console log should be as you expect it.

Further reading: https://mobx.js.org/refguide/action.html https://mobx.js.org/refguide/transaction.html

Tom Riglar
  • 197
  • 1
  • 9
  • Hi! Made this edit / remvoed the @action decorator on chain of method calls but updates still don't reflect on the screen. Added more information, hopefully it helps :) – ali_wetrill Sep 14 '19 at 18:31
0

Try to simplify your code:

    @computed 
    get orderedAttributeKeys() {   
        const orderedAttributeKeys = [];

        Object.entries(this.attributeOrder).forEach(
            ([attrName, index]) => orderedAttributeKeys[index] = this.attributes[attrName])
        );

        return orderedAttributeKeys;
    };

    @action.bound
    changeAttribute(existingAttr, newAttr) {
        // ...
    };

Also rename your Store name, Object is reserved export default class StoreName

zemil
  • 3,235
  • 2
  • 24
  • 33