jorgen
jorgen

Reputation: 3593

Rerendering on async fetch with react-mobx

I'm trying to use mobx-rest with mobx-rest-axios-adapter and mobx-react, and I have trouble making the component rerender upon async data retrieval.

Here's my data model, in state/user.js:

import { Model } from 'mobx-rest';

class User extends Model {
  url() {
    return '/me';
  }
}

export default new User();

This is the React component, in App.js:

import React from 'react';
import { inject, observer } from 'mobx-react';
import { apiClient } from 'mobx-rest';
import createAdapter from 'mobx-rest-axios-adapter';
import axios from 'axios';
import { compose, lifecycle, withProps } from 'recompose';

const accessToken = '...';
const API_URL = '...';

const App = ({ user }) => (
  <div>
    <strong>email:</strong>
    {user.has('email') && user.get('email')}
  </div>
);

const withInitialise = lifecycle({
  async componentDidMount() {
    const { user } = this.props;

    const axiosAdapter = createAdapter(axios);
    apiClient(axiosAdapter, {
      apiPath: API_URL,
      commonOptions: {
        headers: {
          Authorization: `Bearer ${accessToken}`,
        },
      },
    });

    await user.fetch();

    console.log('email', user.get('email'));
  },
});

export default compose(
  inject('user'),
  observer,
  withInitialise,
)(App);

It uses recompose to get the user asynchronously from an API in componentDidMount(), and once available the component is supposed to show the user email. componentDidMount() prints the email once available.

Finally this is index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import createBrowserHistory from 'history/createBrowserHistory';
import { Provider } from 'mobx-react';
import { RouterStore, syncHistoryWithStore } from 'mobx-react-router';
import { Router } from 'react-router';

import App from './App';
import { user } from './state/user';

const documentElement = document.getElementById('ReactApp');

if (!documentElement) {
  throw Error('React document element not found');
}

const browserHistory = createBrowserHistory();
const routingStore = new RouterStore();

const stores = { user };
const history = syncHistoryWithStore(browserHistory, routingStore);

ReactDOM.render(
  <Provider {...stores}>
    <Router history={history}>
      <App />
    </Router>
  </Provider>,
  documentElement,
);

My problem is that the component doesn't rerender once the user is retrieved and the email is available, although the console log shows that it is returned ok in the async request. I've tried playing around with mobx-react's computed, but no luck. Any ideas?

Upvotes: 1

Views: 1044

Answers (1)

Renwei Liu
Renwei Liu

Reputation: 146

I think it will work if you change your compose order of App.js:

export default compose(
  inject('user'),
  withInitialise,
  observer,
)(App);

According to the MobX official document,

Tip: when observer needs to be combined with other decorators or higher-order-components, make sure that observer is the innermost (first applied) decorator; otherwise it might do nothing at all.

Upvotes: 1

Related Questions