5

I have created a store using mobx as follows:

import {extendObservable} from 'mobx';

class InfluencerFeedStore {
    constructor() {
        extendObservable(this, {
            data: []
        });
    }

    setData(items = []) {
        this.data = items;
    }
}

export default new InfluencerFeedStore();

And I then observe that store in my React view:

import React from 'react';
import {observer} from 'mobx-react';
import FeedItem from './FeedItem';
import InfluencerFeedStore from '../../core/stores/InfluencerFeed';

import './style.css';

const generateItems = () => {
    return InfluencerFeedStore.data.map((item, i) => (
        <FeedItem key={`feeditem-${i}`} {...item} />
    ));
};

const Feed = () => (
    <div className="Feed vertical-scroll-flex-child">
        {generateItems()}
    </div>
);

export default observer(Feed);

On first render, my Feed view works just fine (although there are no items in the InfluencerFeedStore.data array).

If I later load items by calling InfluencerFeedStore.setData(), React will correctly attempt to re-render the Feed view (because it noticed the mobx observable updated)... but I get an error complaining that InfluencerFeedStore.data.map is not a function.

From reading through the mobx docs, I gather that re-assigning my data property is problematic because it's an array (whereas other data types like strings "just work"). Can anyone tell me what I'm doing wrong here?

arthurakay
  • 5,631
  • 8
  • 37
  • 62
  • Entirely for my own edification, you seem to be accessing that data val in a static manner, not from an instance of the class (data is initialized in the constructor). Is that ok? ObservableFeed would represent an instance. – Tim Consolazio Dec 01 '16 at 14:46
  • indeed, constructor is never called, so this won't work. Store should be instantiated first – mweststrate Dec 01 '16 at 14:47

2 Answers2

2

So it turns out that I had two problems:

  1. I needed to be using the replace() method to overwrite the observable array, rather than trying to completely reassign a new value
  2. I wasn't actually passing an array into my setData() method; that's why I hit the "map is not a function" error

It should look like this:

import {extendObservable} from 'mobx';

class InfluencerFeedStore {
    constructor() {
        extendObservable(this, {
            data: []
        });
    }

    setData(items = []) {
        this.data.replace(items);
    }
}

export default new InfluencerFeedStore();
arthurakay
  • 5,631
  • 8
  • 37
  • 62
0

Issue is (I think based on my comment) you aren't accessing "data" from an instance of the class, you're accessing it statically, so the constructor of the class never runs, and "data" never initializes. "ObservableFeed" is an instance.

Tim Consolazio
  • 4,802
  • 2
  • 19
  • 28
  • I don't think that's right. In my store file, the only thing I export is I `export default ObservableFeed` -- so when I `import InfluencerFeedStore` it's referencing the same instance object (it's just renamed). Unless I completely misunderstand ES2015 (which IS possible!) – arthurakay Dec 01 '16 at 15:15
  • Hmm...but then wouldn't you want to import the exported member (which would be an instance)? My understanding of ES6 modules is a bit shaky since the builders I use don't support them. But from what you're saying, you can export one thing (ObervableFeed), import another (InfluencerFeedStore), and by doing so, get the behavior of ObervableFeed implicitly somehow? – Tim Consolazio Dec 01 '16 at 15:35
  • I found this, which seems to gel: "There can be only one default export. This is primarily used when you are exporting a single thing, like a class, or a single function that you expect to be used without any additional support. When you import a module with a default export, use import d from c." Would that mean, import ObservableFeed from './etc/InfluencerFeed'? – Tim Consolazio Dec 01 '16 at 15:42
  • Right... so whatever I `export` (ObservableFeed) can be explictly renamed during the `import` (ObservableFeed >>> SomeNewName). Normally you would just use the same variable name for simplicity, but that's how I understand it. – arthurakay Dec 01 '16 at 15:42
  • I also could have just done this: `export default new InfluencerFeedStore();` (EDIT: I updated my code to do just this for simplicity) – arthurakay Dec 01 '16 at 15:44
  • Hmm...I guess at this point, I'd try importing ObservableFeed from your class. If you want to rename it in your import sure go ahead, but otherwise my initial guess (from having worked with other module systems) is that something is missing here such that you're not actually using ObservableFeed. Great conversation here. Bring on the ES6! – Tim Consolazio Dec 01 '16 at 15:45