Q:

I am trying to update a value in an observable every second in setInterval but mobx is giving me error

I am trying to update the coordinates of a marker on a map in react-native. I am using this data that has some set of coordinates. I want the coordinates to upadate. So that I can see the marker moving. I have applied the setInterval in componentDidMount(). I was able to move the marker using state, props and setInterval, but with mobx when I am trying to update the observable in setInterval, I am getting error. The code is given below.
Map.js
import React from "react";
import MapRender from "./MapRender";
import TestData from "./TestData";
import { observable } from "mobx";
import { Provider, observer } from "mobx-react";

export default class Map extends React.Component {
  constructor(props) {
    super(props);
    console.log("TestData.length = ", TestData.response.result.length);
    this.data = TestData.response.result;
  }

  @observable markers = [{
    "_id": "marker",
    "latitude": "26.884815",
    "longitude": "75.7792617",
    "imei": "987654"
  }];

  componentDidMount() {
    let i = 0;
    this.interval = setInterval(() => {
      this.markers[0].latitude = TestData.response.result[i].latitude;
      this.markers[0].longitude = TestData.response.result[i].longitude;
      i++;
      if(i === 100) i = 0;
    }, 1000);
  }

  componentWillUnMount() {
    clearInterval(this.interval);
  }

  render() {
    return (
        <Provider markers={this.markers}>
            <MapRender polylineArray={this.data} />
        </Provider>
    );
  }
}

MapRender.native.js
import React from "react";
import MapView, { Marker, Polyline } from "react-native-maps";
import Box from "../../../grid-styled/src/Box";
import { observable } from "mobx";
import { inject, observer } from "mobx-react";

const DEFAULT_PADDING = { top: 40, right: 40, bottom: 40, left: 40 };
const width = 300;
const height = 300;
const ASPECT_RATIO = width / height;
const LATITUDE_DELTA = 0.0522;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;

@inject("markers")
@inject("manIcon")
@observer
class MapRender extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      region: {
        latitude: 37.78825,
        longitude: -122.4324,
        latitudeDelta: 0.0922,
        latitudeDelta: 0.0922,
        longitudeDelta: 0.0421
      }
    };
    this.drawPolyline = this.drawPolyline.bind(this);
    this.addOrUpdateMarker = this.addOrUpdateMarker.bind(this);
    this.addOrUpdateMarkers = this.addOrUpdateMarkers.bind(this);
  }

  drawPolyline(polylineArray) {
    let polylineArrayFloat = [];
    polylineArrayFloat = polylineArray.map(elem => {
      let returnValue = {};
      returnValue.id = elem.id;
      returnValue.latitude = parseFloat(elem.latitude);
      returnValue.longitude = parseFloat(elem.longitude);
      return returnValue;
    });
    return (
      <MapView.Polyline
        key="polyline"
        coordinates={polylineArrayFloat}
        strokeColor={"blue"}
        fillColor={"rgba(255,0,0,0.5)"}
        strokeWidth={2}
      />
    );
  }

  addOrUpdateMarkers(markers) {
    markers.map(marker => this.addOrUpdateMarker(marker));
  }

  addOrUpdateMarker(marker) {
    let { markers } = this.props;
    var found = markers.find(mark => mark.id == marker.id);
    if (found) {
      found.latitude = marker.latitude;
      found.longitude = marker.longitude;
    } else markers.push(marker);
  }

  drawMarker(marker, i) {
    return (
      <MapView.Marker
        identifier={marker.id}
        coordinate={{
          latitude: parseFloat(marker.latitude),
          longitude: parseFloat(marker.longitude)
        }}
        key={"__marker" + i}
      />
    );
  }

  drawMarkers(markers) {
    this.addOrUpdateMarkers(markers);
    let returnValue = [];
    markers.map((marker, i) => {
      returnValue[i] = this.drawMarker(marker, i);
      if(!React.isValidElement(returnValue[i])) throw Error("Not Valid Element");
    });
    return returnValue;
  }

  render() {
    let { polylineArray, markers } = this.props;
    console.warn(JSON.stringify(markers));
    return (
      <Box h={height} bg="red" w={width}>
        <MapView
          ref={ref => (this.map = ref)}
          style={{ position: "absolute", top: 0, bottom: 0, left: 0, right: 0 }}
          initialRegion={{
            latitude: parseFloat(this.props.polylineArray[0].latitude),
            longitude: parseFloat(this.props.polylineArray[0].longitude),
            latitudeDelta: LATITUDE_DELTA,
            longitudeDelta: LATITUDE_DELTA
          }}
        >
          {this.drawMarkers(markers)}
          {this.drawPolyline(polylineArray)}
        </MapView>
      </Box>
    );
  }
}

export default MapRender;

TestData.js
module.exports = {
    "response": {
        "result": [{
            "_id": "5a31c6b9e9fd1265f115bd21",
            "latitude": "26.884815",
            "longitude": "75.7792617",
            "imei": "987654"
        }, {
            "_id": "5a31ccafe9fd1265f1164beb",
            "latitude": "26.8854983",
            "longitude": "75.7822483",
            "imei": "987654"
        }, {
            "_id": "5a31ccb3e9fd1265f1164c93",
            "latitude": "26.8856533",
            "longitude": "75.7823383",
            "imei": "987654"
        }, {
            "_id": "5a31ccbae9fd1265f1164d68",
            "latitude": "26.885835",
            "longitude": "75.7824267",
            "imei": "987654"
        }, {
            "_id": "5a31ccbee9fd1265f1164e09",
            "latitude": "26.8859617",
            "longitude": "75.7824983",
            "imei": "987654"
        }]
      }
    }

This is the error I am getting
Error: [mobx] Invariant failed: Side effects like changing state are not allowed at this point. Are you trying to modify state from, for example, the render function of a React component? Tried to modify: Map@11.markers[..].latitude

This error is located at:
    in MapRender (created by inject-MapRender-with-markers)
    in inject-MapRender-with-markers (at Map.js:51)
    in Provider (at Map.js:50)
    in Map (at UserRoutes.js:23)
    in Provider (at RouterFP.js:242)
    in RCTView (at View.js:113)
    in View (at StackView.js:44)
    in Provider (at StackView.js:38)
    in StackView (at Nav.js:113)
    in RCTView (at View.js:113)
    in View (at StyledBox.native.js:14)
    in Box (created by Styled(Box))
    in Styled(Box) (at Box.js:34)
    in Container (at Nav.js:112)
    in RCTView (at View.js:113)
    in View (at StyledBox.native.js:14)
    in Box (created by Styled(Box))
    in Styled(Box) (at Box.js:34)
    in Container (at BgBox.native.js:14)
    in BgBox (at Nav.js:110)
    in Provider (at Nav.js:109)
    in Nav (created by inject-Nav-with-backgroundImage)
    in inject-Nav-with-backgroundImage (created by inject-inject-Nav-with-backgroundImage-with-navBodyStyle)
    in inject-inject-Nav-with-backgroundImage-with-navBodyStyle (at ManazeAppFP.js:46)
    in Router (created by inject-Router-with-params)
    in inject-Router-with-params (created by inject-inject-Router-with-params-with-path)

A:

In your <MapRender /> component you are calling addOrUpdateMarker function from render, this function is changing your mobx state.
In that case mobx warn you this is wrong because it may cause a side effect in the render function.

