Tengo un comportamiento extraño de MobX.
Aquí está mi tienda en el archivo store.tsx . Puedes encontrarlo también como sandbox .
import { action, makeObservable, observable} from "mobx"; export default class ViewStore { currentProjectId: string | undefined = undefined; constructor() { makeObservable(this, { currentProjectId: observable, setCurrentProjectId: action, }); } setCurrentProjectId = (projectId: string | undefined) => { this.currentProjectId = projectId; }; }Y aquí está mi componente.
import React from "react"; import { observer } from "mobx-react-lite"; import { useParams } from "react-router-dom"; import ViewStore from "./store"; interface Props { localStore: ViewStore; } interface UrlParams { projectId: string; } function AppManageProject({ localStore }: Props) { const urlParams = useParams<UrlParams>(); if (localStore.currentProjectId !== urlParams.projectId) { localStore.setCurrentProjectId(urlParams.projectId); return <></>; } return ( <div>{localStore.currentProjectId}</div> ); } export default observer(AppManageProject); La página es parte de una aplicación más grande y se accede a ella desde la ruta /<project id> . Cuando navega por primera vez a, por ejemplo, /prj1 , se ejecuta el bloque if, por lo que el currentProjectId observable se establece en "prj1" a través de la acción setCurrentProjectId . Espero que el cambio del observable desencadene una nueva representación, donde ahora urlParams.projectId === localStore.currentProjectId . Pero el componente en realidad no se vuelve a renderizar.
En el sandbox , desde la impresión en la consola, puede ver que ingresa en el bloque if, pero la representación no se activa.
Tenga en cuenta que si en lugar de llamar a la acción setCurrentProjectId directamente, uso una devolución de llamada, por ejemplo, setTimeout(() => localStore.setCurrentProjectId(urlParams.projectId), 0) entonces todo funciona.
Pensando que la devolución de llamada funciona porque usa una función de flecha, también traté de reemplazar
localStore.setCurrentProjectId(urlParams.projectId)con una llamada a una función de flecha:
( () => localStore.setCurrentProjectId(urlParams.projectId) ) ()Pero esto tampoco funciona.
¿Alguien tiene alguna explicación/solución de lo que está pasando? Gracias
Por alguna razón, MobX no vuelve a renderizar los componentes si actualiza algún elemento observable dentro de la función de renderizado. No sé exactamente por qué, pero los efectos secundarios dentro de la función de renderizado son un mal patrón de todos modos, por lo que tiene sentido que no funcione.
Lo que puede hacer para que su código sea más idiomático es usar el gancho useEffect para los efectos secundarios, así:
function AppManageProject({ localStore }: Props) { const urlParams = useParams<UrlParams>(); useEffect(() => { localStore.setCurrentProjectId(urlParams.projectId); }, [urlParams.projectId]); if (localStore.currentProjectId !== urlParams.projectId) { return <></>; } return <div>{localStore.currentProjectId}</div>; }