Search code examples
reactjsimportview

React attempting to replace view, appending instead


I am attempting to make a simple navigation where I am lazily importing views and replacing the "target" with whatever view is selected ... The problem is that my solution APPENDS my view to <MainView /> instead of replacing <MainVies />'s content.

I initially thought about doing something like This Question -- But from what I understand it will import all the views at application load, and you will need to do a full refresh to "re-import" the views ..

import React, {lazy, useState} from 'react';

const importView = viewName =>
    lazy(() =>
        import(`../../layout/views/${viewName}`)
            .catch(() => import(`../../layout/views/Dashboard`))
    );

const MainView = ({views}) =>
    Object.values(views).map(View => (
        <View/>
    ));

export default function App() {
    const [views, setView] = useState({});

    const changeView = viewName => {

        // For debugging if set
        //if (views[viewName]) return;

        const View = importView(viewName);
        setView(c => (
                {...c, [viewName]: View}
            )
        );
    };

    const loadDashboard = () => changeView('Dashboard');
    const loadInbox = () => changeView('Inbox');
    const loadNewsletters = () => changeView('Newsletters');

    return (
        <main>
            <section>
                <button
                    onClick={loadDashboard}>
                    Dashboard
                </button>
                <button
                    onClick={loadInbox}>
                    Inbox
                </button>
                <button
                    onClick={loadNewsletters}>
                    Newsletters
                </button>
            </section>
            <section>
                <React.Suspense fallback="Loading view...">
                    <div className="row">
                        <MainView views={views}/>
                    </div>
                </React.Suspense>
            </section>
        </main>
    );
}

This works .. Except it is appending to the view rather than replacing the view. I am looking to use this as navigation, so I need it to replace the view completely .. I want it to work like standard navigation, switching between views, and import the view every time the button is clicked (in case a view like Inbox has changed, it will import with the updated Inbox view on button click)

What am I doing wrong here?


Solution

  • You can use the state to control the view name, then use a function to render the current view.

    import React, {lazy, useState} from 'react';
    
    const importView = viewName =>
        lazy(() =>
            import(`./${viewName}`)
                .catch(() => import(`./Dashboard`))
        );
    
    export default function App() {
        const [view, setView] = useState(null);
    
    
        const loadDashboard = () => setView('Dashboard');
        const loadInbox = () => setView('Inbox');
        const loadNewsletters = () => setView('Newsletters');
    
        const renderCurrentView = () => {
          const View = importView(view);
    
          return <View />
        }
    
        return (
            <main>
                <section>
                    <button
                        onClick={loadDashboard}>
                        Dashboard
                    </button>
                    <button
                        onClick={loadInbox}>
                        Inbox
                    </button>
                    <button
                        onClick={loadNewsletters}>
                        Newsletters
                    </button>
                </section>
                <section>
                    <React.Suspense fallback="Loading view...">
                        <div className="row">
                            {renderCurrentView()}
                        </div>
                    </React.Suspense>
                </section>
            </main>
        );
    }