I'm new to React and Mobx.
I want to init component by data from GET-request in useEffect(). There are simple component with mobx store:
import { autorun } from "mobx";
import React, { useEffect, useRef } from "react";
import { useStore } from "./store";
const TestPage: React.FC = () => {
const { testStore } = useStore();
const isCancelled = useRef(false);
useEffect(
() => autorun(
() => {
const fetchData = async () => {
const data = await fetch('/api/dictionaries/sources?subject=MATH');
const json = await data.json();
if (!isCancelled.current) {
testStore.setList(json);
}
}
fetchData().catch(console.error);
return () => {
isCancelled.current = true;
};
}
)
, [testStore, testStore.setList]
);
return (
<div>
<h1>This is test list</h1>
{testStore.list.map((i) => <div key={i.id}>{i.id}: {i.name}</div>)}
</div>
);
}
export default TestPage;
test-store.ts:
import { makeAutoObservable } from "mobx";
export interface Item {
id: string;
name: string;
}
export default class TestStore {
list: Item[];
constructor() {
this.list = [];
makeAutoObservable(this);
}
setList = (list: any) => {
this.list = list;
console.log("In setList: " + this.list);
}
}
store.tx:
import { createContext, useContext } from "react";
import TestStore from "./test-store";
const store = {
testStore: new TestStore(),
};
export const StoreContext = createContext(store);
export const useStore = () => {
return useContext<typeof store>(StoreContext);
};
export default store;
Response from server is received, but list in component is not rendered:
However, if recompile to a hot one, the data in the component is rendered. So I think the problem is asynchronous execution. Can I fix it?
For making the React Components reactive to the state changes in mobX, we need to wrap the components an observer(), which is a HoC. You can use either mobx-react or mobx-react-lite both works fine.
import { observer } from "mobx-react-lite"
const Component = observer(() => {
return (
// JSX Codes that uses mobX states
)
})
export default Component
Otherwise, you can also do it like this
import { observer } from "mobx-react-lite"
const Component = () => {
return (
// JSX Codes that uses mobX states
)
}
export default observer(Component)
Only then, you can trigger rerender. Othewise, if you have to use the context API, then I think you have to use useState() to trigger the UI render.