Matúš Čongrády Matúš Čongrády - 3 months ago 90
React JSX Question

Mobx - React: Inject and Observe together

Recently I started using mobx with react and mobx-react library.

I want to use functional React components to create my views.

I'd like to create a helper function, that takes selector function and Component, calls inject (with selector function as parameter) and observe on that Component - effectively connecting this component to mobx-react store (taken from Provider context) and providing only needed properties for this Component.

But I can't get it to work. Action is being dispatched, but views doesn't react to this change (store attributes does change, but Component doesn't react to this change).

Here's my helper function:

import { observer, inject } from 'mobx-react';

export function connect(selectorFunction, component) {
return inject(selectorFunction)(observer(component));
}


here's my Component:

import React from 'react';
import { connect } from 'utils';

const selector = (stores) => {
console.log(stores);
return {
counter: stores.counterStore.counter,
double: stores.counterStore.double,
increment: stores.counterStore.increment
};
};

const Counter = ({ counter, double, increment }) => {
console.log(increment);
return (
<div className="counter">
<p>{ counter }</p>
<p className="double">{ double }</p>
<button onClick={increment}>+1</button>
</div>
);
};

export default connect(selector, Counter);


and here's my store:

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

export default class Counter {
@observable counter = 0;

@action
increment = () => {
this.counter++;
}

@computed
get double() {
return this.counter * 2;
}
}


(Not showing Provider and other simple stuff, but it is set up properly).

Thanks! Every answer is much appreciated.

Answer

Looking at Mobx's documentation, it looks like your selector is doing things a bit wrong. It should return an object with stores, and not an object with values from stores. Try returning the actual counterStore instead:

const selector = (stores) => {
  return {
    counterStore: stores.counterStore
  };
};

And use it like this in your component:

const Counter = ({ counterStore: { counter, double, increment } }) => {
  return (
    <div className="counter">
      <p>{ counter }</p>
      <p className="double">{ double }</p>
      <button onClick={increment}>+1</button>
    </div>
  );
};