Last active
April 7, 2025 10:20
-
-
Save justinline/6ffd8f4b850f8009efc628ba64ce96c9 to your computer and use it in GitHub Desktop.
Digging into mobx + refetching. In this example, the data gets automatically refetched by mobx when the data from another store changes but only when the data that is being observed (in this case poked data) is being used in a mounted component
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { makeAutoObservable } from 'mobx'; | |
import { observer } from 'mobx-react'; | |
import { createContext, useContext } from 'react'; | |
// ====== Stores ====== | |
/** Stores Pokemon Search information */ | |
class PokemonSearchStore { | |
name: string; | |
constructor() { | |
this.name = 'pikachu'; | |
makeAutoObservable(this); | |
} | |
setName(name: string) { | |
this.name = name; | |
} | |
} | |
/** Stores Pokedex API Data */ | |
class PokedexApiStore { | |
pokedexData: {name: string, id: number} | undefined = undefined; | |
pokemonNameStore: PokemonSearchStore; | |
constructor(store: PokemonSearchStore) { | |
this.pokemonNameStore = store; | |
makeAutoObservable(this); | |
} | |
async fetchPokemon() { | |
const name = this.pokemonNameStore.name; | |
if (!name) return; | |
const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${name}`); | |
const data = await response.json(); | |
this.pokedexData = {name: data.name, id: data.id}; | |
} | |
get getPokemon() { | |
this.fetchPokemon(); | |
return this.pokedexData; | |
} | |
} | |
// ====== Providers Stuff ====== | |
const pokemonNameStore = new PokemonSearchStore(); | |
const pokedexApiStore = new PokedexApiStore(pokemonNameStore); | |
const PokemonContext = createContext<{ | |
pokemonNameStore: PokemonSearchStore; | |
pokedexApiStore: PokedexApiStore; | |
}>({ | |
pokemonNameStore, | |
pokedexApiStore, | |
}); | |
const PokedexProvider = ({ children }: { children: React.ReactNode }) => { | |
return <PokemonContext.Provider value={{ pokemonNameStore, pokedexApiStore }}>{children}</PokemonContext.Provider>; | |
}; | |
// ====== Components ====== | |
const PokedexData = observer(() => { | |
const { pokedexApiStore } = useContext(PokemonContext); | |
// Fetching happens here when the component is mounted and the name is changed | |
// If this component is unmounted, the fetch will not happen since the observable is not observed anymore | |
const pokemon = pokedexApiStore.getPokemon; | |
if (!pokemon) return <div>No Pokemon found</div>; | |
return <div>{pokemon.name} - {pokemon.id}</div>; | |
}); | |
const SearchBar = observer(() => { | |
const { pokemonNameStore } = useContext(PokemonContext); | |
return <input type="text" value={pokemonNameStore.name} onChange={(e) => pokemonNameStore.setName(e.target.value)} />; | |
}); | |
export const PokemonTest = observer(() => ( | |
<PokedexProvider> | |
<h1>Pokedex</h1> | |
<SearchBar /> | |
{/** Commenting out the component below results in no network calls being made when search changes. */} | |
<PokedexData /> | |
</PokedexProvider> | |
)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment