Dynamic React Redux Header component in large appl

2019-09-06 09:36发布

问题:

I'm building a Header component which is used throughout my application. I'm using React and Redux (obvz) to hold a default state for the Header e.g. in the header reducer's default state argument:

state = { 
     showUserMenu: true,
     redirectUrl: '/'
}

This is perfect for all the components where this is true, but for some routes/components I want the header to not show the user menu.

So when those components mount I dispatch an action to HIDE_USER_MENU.

The problem is that because the default is set to true, the userMenu will be there initially, and even if the dispatch is called in componentWillMount, there will be a split second where the userMenu shows.

So don't have a default? But then the reverse is true, it defaults to not showing the menu and only appears once the action has processed.

This is nice, but it didn't go just a step further (for my example) and explain how the reducer would be chosen based on either route or component.

I have also tried firing actions based on location.pathname using react-router-redux, but even this does not happen quickly enough to avoid FOUH (flash of unwanted header! :'( )

I wondered if there was an established pattern for dynamically loading an initial state, that is guaranteed to appear on initial render.

Hope it's clear what I was asking, any help much appreciated!

回答1:

The simplest approach is to have the Header be a child of the route. This makes it easy to decide what props to pass: * You don't need to store the header state at all - the routed component can just pass the appropriate props (such as showUserMenu) to the Header.

However, it has a couple of downsides: * All routes have to take care of rendering the Header (not really a problem, there are lots of ways to share the code) * When re-routing, the Header is unmounted and a new one mounted (since its parent, the route component, is unmounted). So any DOM and React state will be lost.

The unmount could be avoided by using the same component type for all your routes (which could render the header), but pass it props to configure the appropriate route handling behaviour (such as a child component).

Another (probably bad) option is for your Header state listen for redux-react-router's LOCATION_CHANGE action, and change the value of showUserMenu based on that. The documentation appears to advise against this, since there can be some asynchronicity before the new route is actually rendered due to dynamic route loading, etc., but it probably works fine for the normal case.