Tworzenie www.carecom.de

Niewielka podróż wyjaśniająca część technologii i programowania stojących za uniwersalną aplikacją jednostronicową carecom.de, opartą na React, TypeScript, Redux i ASP.NET Core.

Harald Mühlhoff 2 min czytania

www.carecom.de to uniwersalna (izomorficzna) aplikacja jednostronicowa (SPA) w React z wykorzystaniem Redux, React-Router, TypeScript, Bootstrap oraz backendu ASP.NET Core.

Opiera się na znakomitym projekcie Microsoft ASP.NET Core JavaScript Services. Część rozszerzeń pochodzi od świetnej społeczności na GitHubie, inne zaimplementowałem samodzielnie:

  • Obsługa wielu najemców (multi-tenant), bym mógł łatwo wykorzystać całą tę dobroć dla moich klientów
  • Lokalizacja (po stronie klienta i serwera)
  • Tagi meta i tytuły
  • Dodany komponent Google Analytics
  • Dodany komponent Google Ads
  • Dodany komponent ostrzeżenia o plikach cookie
  • Dodany komponent przełącznika cen brutto / netto
  • Dodana podstawowa obsługa uwierzytelniania
  • Dodany komponent okna modalnego
  • Dodany komponent formularza kontaktowego
  • Dodany komponent formatowania kodu
  • Dodany komponent płynnego przewijania / przewijania do hashtagu
  • Sitemap.xml
  • Przekazywanie „stanu globalnego" między serwerem a klientem
  • Ulepszona obsługa plików cookie
  • Zagnieżdżone reduktory redux
  • ...

Z czasem będę rozbudowywał ten wpis, opisując więcej aspektów projektu aplikacji. Wyjaśnianie technologii leżących u podstaw wykracza poza zakres tego wpisu.

Na razie jest to bardziej zalążek tego, co nadejdzie.

Uwielbiam:

  • jak łatwo Redux pozwala tworzyć komponenty wielokrotnego użytku – albo po prostu komponenty „w locie", jak:
    let PhotographySlider = (props) =>
            <Slider id="PhotographySlider" baseUrl="/tenants/carecom/images/photography/slides/" fromNr={1} toNr={42} />
  • elegancję ES6, taką jak destrukturyzacja obiektów:
    es6 destructuring objects

Przyjrzyjmy się fragmentowi głównego komponentu Layout napisanego w React (z użyciem JSX; kod w {} to TypeScript) dla tej strony:

        return <div className="layoutContainer">
            <DocumentMeta {...getMeta()} />

            <NavMenu userId={this.props.userId} isLoggedIn={this.props.isLoggedIn} onLogout={this.props.onLogout} />
            {this.props.slider}

            <main className='container mainLayoutContainer'>
                {
                    breadCrumb &&
                    <div className='row hidden-xs hidden-sm'>
                        <div className='col-md-6 breadCrumb'>{breadCrumb}</div>
                    </div>
                }

                {
                    title &&
                    <div className='row'>
                        <header className={`col-md - ${(side ? 0 : 3) + (translations ? 6 : 9)} col-xs - ${ translations ? 9 : 12 } `}>
                            <h1>{title}</h1>
                        </header>

                        {
                            translations &&
                            <div className='col-xs-3 translations'>
                                <span className='glyphicon glyphicon-flag'></span>&nbsp;{translations}
                            </div>
                        }
                    </div>
                }

                <div className='row'>
                    <div className={`col- md - ${side ? 9 : 12 }`} role='main'>{ this.props.body }</div>

                    {
                        side &&
                        <aside className='col-md-3'>{ side }</aside>
                    }
                </div>

            </main>

            <footer>
                <BottomMenu />
                <Footer />
            </footer>
        </div>

DocumentMeta (z React Document Meta) zapewnia, że informacje takie jak title, description i tagi meta zostaną powiązane z komponentem korzystającym z tego Layoutu. getMeta() pochodzi z modułu pomocniczego, który pobiera metadane dla bieżącej trasy.

Breadcrumb, tytuł i tłumaczenia (linki do innych wersji językowych danej trasy) będą renderowane tylko wtedy, gdy dostarcza je bieżąca trasa.

export default (
    <Route path='/' component={Layout}>
        { /* de */ }
        <IndexRoute components={EnhHomeComp} />

        <Route path="de">
            <IndexRoute components={EnhHomeComp} />

            <Route path='consulting'>
                <IndexRoute components={{ body: Consulting, side: ConsultingQuotation }} />
                <Route path='informatiker' components={{ body: ComputerScientist, side: SideHaraldMuehlhoff }} />
                <Route path='referenzen' components={{ body: ConsultingReferences }} />
                <Route path='remote-support' components={{ body: RemoteSupport, side: SideHaraldMuehlhoff }} />
            </Route>

            <Route path='distribution'>
                <IndexRoute components={{ body: Distribution, side: DistributionQuotation }} />
                <Route path='referenzen' components={{ body: DistributionReferences }} />
                <Route path='selbstbedienung' components={{ body: SelfService }} />
            </Route>

Np. nie każda Route ma komponent side. Ma to wpływ na zastosowane style Bootstrap (className={`col-md-${side ? 9 : 12}`}).

Wystąpił błąd. Załaduj ponownie 🗙

Ponowne łączenie z serwerem …

Ponowne połączenie nie powiodło się – następna próba za s.

Ponowne połączenie nie powiodło się.
Spróbuj ponownie lub załaduj stronę od nowa.

Serwer wstrzymał sesję.

Nie udało się wznowić sesji.
Spróbuj ponownie lub załaduj stronę od nowa.