Search code examples
javascriptreactjstypescriptaxiosmobx-react

React Mobx can't display observable contents, very simple app


Very simple app, I'm trying to display content from my API using Mobx and Axios, here's my Axios agent.ts:

import { ITutorialUnit } from './../model/unit';
import axios, { AxiosResponse } from "axios";

//set the base URL
axios.defaults.baseURL = "http://localhost:5000/api";

//store our request in a const
const responseBody = (response: AxiosResponse) => response.data;

const requests = {
  get: (url: string) => axios.get(url).then(responseBody),
};

//create a const for our activty's feature,all our activities' request are go inside our Activities object
const TutorialUnits = {
  list: ():Promise<ITutorialUnit[]> => requests.get("/tutorialunits"),
};

export default{
    TutorialUnits
}

then I call this agent.s in a store:

import { ITutorialUnit } from "./../model/unit";
import { action, observable } from "mobx";
import { createContext } from "react";
import agent from "../api/agent";

class UnitStore {
  @observable units: ITutorialUnit[] = [];
  //observable for loading indicator
  @observable loadingInitial = false;

  @action loadUnits = async () => {
    //start the loading indicator
    this.loadingInitial = true;
    try {
      //we use await to block anything block anything below list() method
      const units = await agent.TutorialUnits.list();
      units.forEach((unit) => {
        this.units.push(unit);
      //  console.log(units);
      });
      this.loadingInitial = false;
    } catch (error) {
      console.log(error);
      this.loadingInitial = false;
    }
  };
}
export default createContext(new UnitStore());

then I call this in my App component:

import React, { Fragment, useContext, useEffect } from "react";
import { Container } from "semantic-ui-react";
import "semantic-ui-css/semantic.min.css";
import NavBar from "../../features/nav/NavBar";
import { ActivityDashboard } from "../../features/Units/dashboard/tutorialUnitDashboard";
import UnitStore from "../stores/unitStore";
import { observer } from "mobx-react-lite";
import { LoadingComponent } from "./LoadingComponent";

const App = () => {
  const unitStore = useContext(UnitStore);
  
  
  useEffect(() => {
    unitStore.loadUnits();
    //need to specify the dependencies in dependenciy array below
  }, [unitStore]);
  //we are also observing loading initial below 
  if (unitStore.loadingInitial) {
    return <LoadingComponent content="Loading contents..." />;
  }

  return (
    <Fragment>
      <NavBar />
      <Container style={{ marginTop: "7em" }}>
        <ActivityDashboard />
      </Container>
    </Fragment>
  );
};

export default observer(App);

Finally, I want to use this component to display my content:

import { observer } from "mobx-react-lite";
import React, { Fragment, useContext } from "react";
import { Button, Item, Label, Segment } from "semantic-ui-react";
import UnitStore from "../../../app/stores/unitStore";

const UnitList: React.FC = () => {
  const unitStore = useContext(UnitStore);
  const { units } = unitStore;
  console.log(units)
  return (
    <Fragment>
      {units.map((unit) => (
        <h2>{unit.content}</h2>
      ))}
    </Fragment>
  );
};

export default observer(UnitList);

I can't see the units.. Where's the problem? My API is working, I tested with Postman. Thanks!!


Solution

  • If you were using MobX 6 then you now need to use makeObservable method inside constructor to achieve same functionality with decorators as before:

    class UnitStore {
      @observable units: ITutorialUnit[] = [];
      @observable loadingInitial = false;
    
      constructor() {
        // Just call it here
        makeObservable(this);
      }
    
      // other code
    }
    

    Although there is new thing that will probably allow you to drop decorators altogether, makeAutoObservable:

    class UnitStore {
      // Don't need decorators now anywhere
      units: ITutorialUnit[] = [];
      loadingInitial = false;
    
      constructor() {
        // Just call it here
        makeAutoObservable(this);
      }
    
      // other code
    }
    

    More info here: https://mobx.js.org/react-integration.html