nareshbhatia / mobx-state-router

MobX-powered router for React apps
https://nareshbhatia.github.io/mobx-state-router/
MIT License
227 stars 30 forks source link

Param change doesn't trigger a re-render #89

Closed idrm closed 4 years ago

idrm commented 4 years ago

When the view map points multiple routes to the same component with only the route and params differing it does not trigger a re-render. See https://codesandbox.io/s/eager-sound-fi6z0 for an example

idrm commented 4 years ago

My initial assessment that the issue may be due to the same component being used multiple times in the view map was incorrect.

Here's an updated sandbox that better demos the issue: https://codesandbox.io/s/objective-solomon-49m5u

After some tinkering with the library code I came up with the following update to RouterView.tsx to fix the issue. I tweaked the view map to also accept a function that resolves to a ReactNode (the current version of the library accepts only instances of ReactNode). You can see it used in this sandbox (the only difference with the sandbox mentioned previously is this custom RouterView component): https://codesandbox.io/s/blissful-bohr-nhevt

import React, { Fragment } from 'react';
import Debug from 'debug';
import { observer } from 'mobx-react';
import { useRouterStore } from '../contexts';

const debug = Debug('msr:RouterView');

export interface ViewMap {
    [routeName: string]: React.ReactNode | (() => React.ReactNode); // CHANGED THIS LINE
}

export interface RouterViewProps {
    viewMap: ViewMap;
}

/**
 * Watches the router state and instantiates the associated UI component.
 * It expects two props: the `routerStore` and a `viewMap`. The `viewMap`
 * is a simple mapping from `routeNames` to React components.
 */
export const RouterView: React.FC<RouterViewProps> = observer(({ viewMap }) => {
    const routerStore = useRouterStore();
    const { routerState } = routerStore;
    debug('render %o', routerState);

    const view = viewMap[routerState.routeName];
    return view ? <Fragment>{typeof view === 'function' ? view() : view}</Fragment> : null; // CHANGED THIS LINE
});
nareshbhatia commented 4 years ago

Hi @idrm. I looked at your example. The router is in fact changing the state correctly. However the Department page is not detecting the state change because it is not an observer. The moment I made it an observer, everything started to work correctly. Please see here: https://codesandbox.io/s/twilight-river-dh6pq?file=/src/DepartmentPage.tsx