TurtleTread
TurtleTread

Reputation: 1314

MobX autorun not working class component constructor

React is actually unbelievably hard T_T....

I just want to invoke a component method when there's a state change. I can do this easily with a watcher in Vue. But what am I supposed to do in React class component and MobX's autorun? Would this work in a functional component instead?

import someStore 

@observer
class MyComponent {
    constructor(){
       autorun( 
         // references someStore.someObservable
         // call component methods 
         // but this isn't hit when there's change
        )
    }
}

Upvotes: 0

Views: 1475

Answers (1)

Danila
Danila

Reputation: 18476

I've made 2 examples for you, one with class component which is not recommended way to do things anymore, and one with functional component.

Example is quite escalated, because it would be much easier to compute our status in render, but let's pretend we can't do that and we want to invoke some internal method.

First, we setup out store and update it every second:

import { observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import React, { useEffect, useState } from 'react';

const store = observable({
  counter: 0
});

setInterval(() => {
  store.counter++;
}, 1000);

// Helper method
const getStatus = (number) => (number % 2 === 0 ? 'even' : 'odd');

Here is our functional component, we use useEffect to react to counter changes and then update our internal state with setStatus method:

const CounterFunctional = observer(() => {
  const [status, setStatus] = useState(() => getStatus(store.counter));

  useEffect(() => {
    setStatus(getStatus(store.counter));
  }, [store.counter]);

  return <div>functional: {status}</div>;
});

Here is our class component, now we use MobX reaction (don't forget to dispose it on unmount) and similarly update our internal state after counter changes:

const CounterClass = observer(
  class extends React.Component {
    disposer;

    constructor() {
      super();

      this.state = {
        status: getStatus(store.counter)
      };
    }

    componentDidMount() {
      this.disposer = reaction(
        () => store.counter,
        () => {
          this.setState({
            status: getStatus(store.counter)
          });
        }
      );
    }

    componentWillUnmount() {
      this.disposer();
    }

    render() {
      return <div>class: {this.state.status}</div>;
    }
  }
);

Hope it makes sense, React is actually super easy library :)

Codesandbox: https://codesandbox.io/s/httpsstackoverflowcomquestions66602050-7uhm6

Upvotes: 1

Related Questions