Search code examples
javascriptreactjsmobxmobx-react

react/mobX : best practice


I'm fairly new to React and MobX. I've read/watched a lot tutorials on react and react in combination with MobX.

I need to create a form, where a user can select (autocomplete) a product. I'm using react-select to do this. When a user selects a product, the interface needs to update another select with locations for the selected product (which I didn't implement yet, but it will use the options from the location observable).

  • Are there any 'best practices' on how to set up the communication between the react elements and MobX?
  • The 'findProduct' and the 'findLocationAllocationData ' are defined as an action. is this correct?

Thanks for your help!

    const {observable, action} = mobx;
    const {observer}           = mobxReact;
    
    class MyStore {
      product = observable({value: null});
      locations= observable({value: null,options: [],disabled: true});
    
      findProduct = action((input, callback) => {
        //ajax call to get products
        // JSON object as an example

        callback(null, {
          options: [{key: 1, value: 1, label: 'product a'},
            {key: 2, value: 2, label: 'product b'}
          ],
          complete: true
        })
      });
    
      findLocationAllocationData = action(() => {
          if (null === this.product.value) {
            return;
          }
    
          //ajax-call to get the locations and to update the location observable options
        }
    }

And the react stuff:

 class Well extends React.Component {
        render() {
          return ( 
            <div className = "well" >
              <span className = "well-legend" > {this.props.legend} < /span> 
              {this.props.children} 
           </div>
         );
      }
    }
    
    class FormGroup extends React.Component {
      render() {
        return ( 
        <div className = "form-group" >
            <label htmlFor = {this.props.labelFor} > 
              {this.props.label} 
            </label> 
            {this.props.children} 
        </div>
      );
    }
    }
    
    const ProductSelect = observer(class ProductSelect extends React.Component {
      onChange = (e = null) => {
        this.props.store.product.value = null !== e ? e.value : null;
        this.props.store.findLocationAllocationData();
      };
    
      getOptions = (input, callback) => {
        this.props.store.findProduct(input, callback);
      };
    
      render() {
        const product = this.props.store.product;
    
        return ( 
        <Select.Async 
          id = "product"
          name = "product"
          className = "requiredField"
          loadOptions = {this.getOptions}
          onChange = {this.onChange}
          value = { product.value}
          />
        );
      }
    });

const MyForm = observer(class MyForm extends React.Component {
  render() {
    const store = this.props.store;

    return ( 
      <div>
        <form >
          <Well legend="Step 1 - Product">
            <div className="row">
              <div className="col-md-4">
                <FormGroup label="Product" labelFor="product">
                  <ProductSelect store={store} /> 
                </FormGroup> 
              </div> 
            </div> 
        </Well> 
     </form> 
    </div>
    )
  }
});


const myStore = new MyStore();

ReactDOM.render( 
    <MyForm store={myStore}/>, document.getElementById('root')
);

Solution

  • Your actions functions are fine but you must be aware: actions only affects the currently running function. You may want to create a callback action like findLocationAllocationData-callback and findProduct-callback

    More info here

    MobX is not an architecture you can structure your code as you wish there are no best practices. You may want to separate your actions and your API calls.

    You can take a look for this repo for inspiration.