MobX not updating React view when pushing to an array

user818700 picture user818700 · Aug 23, 2017 · Viewed 7.7k times · Source

My Store.js:

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

useStrict(true);

export const state = observable({

    contacts: []

});

export const actions = {

    addContact: action((firstName, lastName) => {
        state.contacts.push({
            id: Math.floor((Math.random() * 1000) + 1),
            firstName: firstName,
            lastName: lastName
        });
    })

};

My index.js:

import React from 'react';
import { Provider } from 'mobx-react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { state, actions } from './Store';

ReactDOM.render(
    <Provider state={state} actions={actions}>
        <App />
    </Provider>,
    document.getElementById('root')
);
registerServiceWorker();

My App.js:

import React, { Component } from 'react';
import ContactList from './components/ContactList';
import ContactAdder from './components/ContactAdder';
import { observer, inject } from 'mobx-react';

const App = inject('state', 'actions')(observer(class App extends Component {
  render() {
    return (
      <div>

        <h1>Contacts</h1>

        <ContactList
          contacts={this.props.state.contacts}
          onDelete={this.props.actions.removeContact}
        />

        <ContactAdder onAdd={this.props.actions.addContact} />

      </div>
    );
  }
}));

export default App;

And finally my ContactAdder.js:

import React, { Component } from 'react';

class ContactAdder extends Component {

    render() {
        return (
            <div className='ContactAdder'>
                <input type='text' value='' placeholder='First Name' />
                <input type='text' value='' placeholder='Last Name' />
                <button onClick={this.props.onAdd.bind(this, 'Test', 'Testerson')}>Add</button>
            </div>
        );
    }

}

export default ContactAdder;

After addContact() runs in Store.js I can see, when I do a console log, that the array does get mutated. But for some reason my view isn't reacting. What am I doing wrong?

Answer

Tholle picture Tholle · Aug 24, 2017

Without seeing your ContactList component, I think the issue would be resolved if you just make that into an observer as well.

An observer component will re-render once the observables that got de-referenced in the previous render are changed. The this.props.state.contacts does not de-reference your contacts array. It would work if you wrote this.props.state.contacts.slice() or this.props.state.contacts.peek(), but that is generally only used when passing observables to external libraries.

You might just as well make all your components that use observables into observers to be as efficient as possible.