DEV Community

NDREAN
NDREAN

Posted on • Edited on

POST with Mobx in functional React component

This is the second post on the discovery of Mobx. We make a stateless functional component that makes asynchronous POST requests, with no classes nor decorators. It is a continuation of the previous post which showed how to use Mobx in functional React form stateless component.

Code linting

We use the helper <React.StrictMode> and the following config for Mobx to detect errors.

#index.js
import { configure } from "mobx";
configure({
  enforceActions: "always",
  computedRequiresReaction: true,
  reactionRequiresObservable: true,
  observableRequiresReaction: true,
  disableErrorBoundaries: true,
});
Enter fullscreen mode Exit fullscreen mode

Guideline

We follow the Mobx async guides.

The component

We will build a very simple React component that displays an input and POST it to some API. Then we display the response from the server. The fetched data will be stored in the object myStore

Imports from Mobx

Our imports are:

import React, { useState } from "react";
import { observable, action, runInAction } from "mobx";
import { observer } from "mobx-react-lite"
Enter fullscreen mode Exit fullscreen mode

These imports are used with the following rules:

  • wrap the event handlers with action
  • wrap the asynchronous call with runInAction(()=> [...]) or use the IIEE form action(()=>[...])()
  • wrap a component with observer whenever you access to observable values,
  • wrap the store with observable

The Store

The state is an object, named myStore here, and contains the observables, the values and methods that may be changed by the component: the input - uncontrolled value here - name and the returned result from the server and a rendering method.
A component may still have a local state; for example, the loading state is naturally local to each component.

#myStore.js
import React from "react";
import { observable } from "mobx";

const myStore = observable({
  name:"",
  result: [],
  getResult(bool) {
    return bool ? Loading() : myStore.result;
  },
});
Enter fullscreen mode Exit fullscreen mode

with the helper:

const Loading = () => <span>Loading ...</span>;
Enter fullscreen mode Exit fullscreen mode

The code

The whole component is wrapped by observer since we access to observable values.
The onSubmit handler is wrapped with action. The component doesn't use an internal state for the data nor use useEffect. Instead, the state mutation will be handled by runInAction, an "autorun" form of action (the IIEF form of action can also be used).

#FormPstMobx.js

export const FormPostMobx = observer(({store}) => {
  const [isLoading, setIsLoading] = useState(false);

  const handleSubmit = action(async (e) => {
    e.preventDefault();
    setIsLoading(true);
    const formData = new FormData(e.currentTarget);
    // Object.fromEntries(formData) to check
    try {
      const query = await fetch("url", {
        method: "POST",
        mode: "cors",
        body: formData,
      });

      if (query) {
        const res = await query.json();
        runInAction(()=> store.result = res)
        // or action(() => { store.result = res })()
      }
    } catch (error) {
      console.error("Error ", error);
      throw error;
    } finally {
      setIsLoading(false);
    }
  });
Enter fullscreen mode Exit fullscreen mode

We return a standard form with uncontrolled input. The last line displays conditionally whether the Loader or the results. This method comes from the store as per the Mobx linting.

  return (
    <>
      <form onSubmit={handleSubmit} >
        <input type="text" name="data[name]" defaultValue={store.name}  />
        <button>Enter</button>
      </form>
      <p>{store.getResult(isLoading)}</p>
    </>
  );
});
Enter fullscreen mode Exit fullscreen mode

and we can use:

#index.js
import ReactDom from "react-dom";
import { myStore } from "./store";
import { FormPostMobx} from "./FormPostMobx.js

ReactDom.render(
  <React.StrictMode>
    <FormPostMobx store={myStore}/>
  </React.StrictMode>,
  document.getElementById('root')
)
Enter fullscreen mode Exit fullscreen mode

Conclusion

With very little change in the code, we can use Mobx with asynchronous calls. This makes the component stateless. We then can continue and enjoy a simple way to use a central store so the data can be distilled easily within the rest of the components.

Top comments (0)