I create a Mobx State Tree global state composed by a DataModel
that contains a TranslationsDataModel
. In DataModel
I created a fetchDataset
function that I would like to call in TranslationsDataModel
but I get an error saying that fetchDataset
is not a function and I don't understand why.
This is my code:
index.ts
:
export const StateModel = types.model('StateModel', {
data: types.optional(DataModel, {} as DataModelInstance),
})
export const stateInstance = StateModel.create()
export interface StateInstance extends Instance<typeof StateModel> {}
const RootStateContext = createContext<StateInstance | null>(null)
export const Provider = RootStateContext.Provider
export function useMst() {
const state = useContext(RootStateContext)
if (state === null) {
throw new Error('')
}
return state
}
DataModel.ts
:
export const DataModel = types
.model('DataModel', {
translations: types.optional(TranslationsDataModel, {} as TranslationsDataModelInstance),
})
.views((self) => ({
get root() {
return getRoot(self)
},
}))
.actions((self) => ({
fetchDataset: flow(function* fetchDataset<T>(dataUrl: string) {
try {
const dataset: T[] = yield fetchCsvDataset<T>(dataUrl)
return dataset
} catch (error) {
console.log(`! Error: ${error}`)
return []
}
}),
}))
export interface DataModelInstance extends Instance<typeof DataModel> {}
TranslationsDataModel.ts
:
const TranslationDatum = types.model('TranslationDatum', {
key: types.string,
text: types.string,
})
export const TranslationsDataModel = types
.model('TranslationsDataModel', {
translationsDataset: types.optional(t.array(TranslationDatum), []),
})
.views((self) => ({
get root(): DataModelInstance {
return getRoot(self)
},
}))
.views((self) => ({
getTranslation(key: string) {
return '...'
}
}))
.actions((self) => ({
updateTranslationsDataset(dataset: Translation[]) {
self.translationsDataset.replace(dataset)
},
}))
.actions((self) => ({
async afterCreate() {
const translationsDataset = await self.root.fetchDataset<Translation>('translations.csv')
self.updateTranslationsDataset(translationsDataset)
},
}))
export interface TranslationsDataModelInstance extends Instance<typeof TranslationsDataModel> {}
I used the stores in that way:
const Homepage = observer(() => {
const {
data: {
translations: { getTranslation },
},
} = useMst()
return (
<div>{getTranslation('title')}</div>
)
})
at line const translationsDataset = await self.root.fetchDataset<Translation>('translations.csv')
I get Uncaught (in promise) TypeError: self.root.fetchDataset is not a function
. What's the problem?
Here in your example fetchDataset
function is defined in the DataModel
, and you're trying to call it using self.root.fetchDataset
from TranslationsDataModel
, however, the fetchDataset
function is not directly accessible through self.root
and this should be the reason why the error occured
you should define an action in TranslationsDataModel
that calls the fetchDataset
function from the DataModel
:
export const TranslationsDataModel = types
.model('TranslationsDataModel', {
translationsDataset: types.optional(t.array(TranslationDatum), []),
})
.views((self) => ({
get root(): DataModelInstance {
return getRoot(self)
},
}))
.views((self) => ({
getTranslation(key: string) {
return '...'
}
}))
.actions((self) => ({
updateTranslationsDataset(dataset: Translation[]) {
self.translationsDataset.replace(dataset)
},
async fetchTranslationsDataset() {
const translationsDataset = await self.root.fetchDataset<Translation>('translations.csv')
self.updateTranslationsDataset(translationsDataset)
},
}))
.actions((self) => ({
async afterCreate() {
await self.fetchTranslationsDataset();
},
}));
export interface TranslationsDataModelInstance extends Instance<typeof TranslationsDataModel> {}
You can now call self.fetchTranslationsDataset()
within the afterCreate
action to initiate the data fetching process using the function from the parent model DataModel
.