preactjs / preact-router

:earth_americas: URL router for Preact.

Home Page:http://npm.im/preact-router

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Router unmounts Routes on parent re-render

orangecoloured opened this issue · comments

commented

I have this state in my root component which is passed then as a context value

export const GlobalStateContext = createContext({
    stateGlobal: stateGlobalInitial,
    setStateGlobal: (_state: Partial<AppStateProps>) => { return },
})

const [stateGlobal, setStateGlobal] = useReducer<AppStateProps, Partial<AppStateProps>>(
    (state, newState) => ({ ...state, ...newState }),
    stateGlobalInitial,
)

const contextValue = useMemo(
    () => ({ stateGlobal, setStateGlobal }),
    [stateGlobal]
)

<GlobalStateContext.Provider value={contextValue}>
    <Menu />
</GlobalStateContext.Provider>

On each update components inside the <Router> get re-mounted.
Components sitting outside of the <Router> act normal.

const A: FunctionalComponent = () => {
    useEffect(() => {
        console.log('MOUNTED')

        return (): void => {
            console.log('UNMOUNTED')
        }
    }, [])

    return <div>yo</div>
}

<div id="root">
    <GlobalStateContext.Provider value={contextValue}>
        <Menu />
    </GlobalStateContext.Provider>
    <div>
        <Router>
            <Route path="/" component={A} />
        </Router>
    </div>
</div>

So in the above example on each contextValue update you get UNMOUNTED in the console.
Is there a way to fix this behaviour? Or am I doing something wrong?

It seems like you're creating a new A function on every render. Components should never be created within another component or render method, since that breaks referential equality and causes them to remount on every update.

Does not work Works
function App() {
  const A: FunctionalComponent = () => {
    useEffect(() => {
      console.log('MOUNTED')

      return (): void => {
        console.log('UNMOUNTED')
      }
    }, [])

    return <div>yo</div>
  }

  return (
    <div id="root">
      <GlobalStateContext.Provider value={contextValue}>
        <Menu />
      </GlobalStateContext.Provider>
      <div>
        <Router>
          <Route path="/" component={A} />
        </Router>
      </div>
    </div>
  );
}
const A: FunctionalComponent = () => {
  useEffect(() => {
    console.log('MOUNTED')

    return (): void => {
      console.log('UNMOUNTED')
    }
  }, [])

  return <div>yo</div>
}

function App() {
  return (
    <div id="root">
      <GlobalStateContext.Provider value={contextValue}>
        <Menu />
      </GlobalStateContext.Provider>
      <div>
        <Router>
          <Route path="/" component={A} />
        </Router>
      </div>
    </div>
  );
}
commented

@developit I think you are right. I've already updated my code to avoid this re-mount, but probably the previous logic was re-creating the component. Thank you.