javascript - Hvordan bør barnekomponenter i React kommunisere med hverandre på en ryddig og vedlikeholdbar måte?


Jeg er forholdsvis ny i React, og jeg prøver å forstå en ryddig måte for barnekomponenter å kommunisere med hverandre på.

I en enkel komponent vet jeg at jeg kan bruke props for å sende data til barn og callback-funksjoner for at barn skal kunne sende data tilbake til foreldrekomponenten.

I et litt mer komplekst tilfelle, når jeg har flere barnekomponenter i en foreldrekomponent, blir kommunikasjonen mellom barna litt forvirrende. Jeg er ikke sikker på hva jeg bør gjøre for at barnekomponenter på samme nivå skal kommunisere med hverandre.

I mitt tilfelle bestemte jeg at kanskje jeg kunne bruke states. Så jeg vil ha en state-verdi i foreldreskomponenten, og sende den videre til barnas props. På samme måte vil callback-handlerne (kalt fra barnekomponenten) i foreldreskomponenten hjelpe til med å sette states tilsvarende, slik at en state-verdi blir sendt videre fra ett barn til et annet gjennom Reacts binding.

Og en pseudokode kunne se omtrent slik ut:

//Inside Parent Component
constructor() {
   //initialise state for the child components
   this.setState({testList: []});
}

render() {
    return (
        <div>
            <ChildA onSomething={this.onSomethingHandler} testList={this.state.testList} />
            <ChildB onSomethingElse={this.onSomethingElseHandler} testList={this.state.testList} />
        </div>
    );
}

onSomethingHandler(evt):void {
    if(blah.blah.blah) this.setState({testList: this.state.testList.splice().push(evt.value)};
}

onSomethingElseHandler(evt):void {
    //Some other complex biz logic...
    if(blah.blah.blah) this.setState({testList: this.state.testList.splice().push(somethingOtherStuffDueToLogic)};
}

//Inside ChildA Component
export IChildAProps {
    onSomething: (evt)=>void
}

render() {
    //Do some logic from the value in testList property
    if(this.state.testList == blah blah)...

    return (
        <button onClick={this.props.onSomething({id:321, value:"wassup! I'm ChildA."})}>ChildA</button>
    )
}

//Inside ChildB Component
export IChildBProps {
    onSomethingElse: (evt)=>void
}

render() {
    //Do some logic from the value in testList property
    if(this.state.testList == blah blah)...

    return (
        <button onClick={this.props.onSomething({id:123, value:"yo! I'm ChildB."})}>ChildB</button>
    )
}

På dette tidspunktet begynner jeg å lure på om logikken i de to håndteringsmetodene, nemlig onSomethingHandler() og onSomethingElseHandler() i Parent-komponenten, egentlig burde ligge inne i selve barnekomponentene? Jeg tenkte på dette fordi logikken ser ut som noe barnekomponenten burde håndtere selv for å oppfylle sitt formål. Parent-komponenten burde ikke gjøre det for dem, ellers kan det bare bli rotete. Men jeg har ikke noe valg på grunn av hvordan jeg håndterer kommunikasjonen deres. I tillegg har jeg også opprettet en ny state bare for å tillate dem å kommunisere.

Så langt er dette fortsatt relativt håndterbart. Men i mitt eget eksperiment har det kommet til et stadium hvor jeg har barnekomponenter innebygd i andre barnekomponenter som trenger å kommunisere på tvers av andre barnekomponenter på samme (eller noen ganger forskjellig) nivå. Å bruke states for kommunikasjon betydde også at jeg har mange states overalt, noe som ikke ser ut som en god idé for meg. Og foreldrekomponentene endte opp med et hav av rotete callback-metoder for å håndtere all denne data-propagasjonen opp og ned i komponenttreet.

Situasjonen er så rotete at jeg høyst sannsynlig bare kan illustrere den som noe slikt:

Og du kan se i illustrasjonen ovenfor at ChildB endte opp med å ha enda en tilstand bare for å hjelpe med å sende den informasjonen mellom sine barnekomponenter.

Jeg er sikker på at jeg går glipp av noe jeg burde vite om React. Tilbakekallingsfunksjonene jeg har i foreldreakomponentene virker litt mye bare for å håndtere dataspredning. Hvordan bør jeg egentlig organisere kommunikasjonen mellom barnekomponenter på en ren og vedlikeholdbar måte?

Svar #1

Hver React-programmer treffer denne muren på et tidspunkt. Det gjorde jeg også. Svaret er å bruke Redux for tilstandsadministrasjon. Du har erfart hvor tidkrevende det er å bruke Reacts native tilstand.

Redux er en statshåndteringsmekanisme som kan brukes sammen med React. Så du vil ikke bruke Reacts state, i stedet vil du bruke Redux.

Redux tilbyr en enkelt butikk, hvor tilstanden til hele applikasjonen lagres. Du kan få tilgang til tilstanden i komponentene dine ved å bruke connect()-metoden.

Men det er en forbehold. Ikke alle React-komponentene er koblet til Redux-butikken. Det finnes to typer komponenter-

  • Smartenheter/tilkoblede komponenter: Tilkoblet Redux-lager
  • Enkle komponenter: Avhengig av tilkoblede komponenter

Ideen er å sende staten fra Redux-lageret til tilkoblede komponenter via Reacts props. De tilkoblede komponentene kan bruke staten direkte fra lageret. De enkle komponentene er ikke direkte koblet til Redux-lageret. De tilkoblede komponentene sender også staten til de enkle komponentene via props. Så du ser, Reacts state blir helt forbigått. Nå, hvis du vil endre staten, må følgende hendelser skje-

  1. En hendelse utløses fra den smarte/dumme komponenten.
  2. Handlinger sendes til store
  3. Reducers lager en ny tilstand i henhold til actions.
  4. En ny tilstand vil bli lagret i store.
  5. Store vil returnere ny tilstand til de tilkoblede komponentene via connect() gjennom props
  6. Tomme komponenter vil motta ny tilstand fra tilkoblede komponenter gjennom props

Hva er handlinger og reduktorer?

Handlinger er bare JavaScript-objekter som beskriver hvordan man endrer tilstanden.

Reducer er en "ren" funksjon som bygger og returnerer det nye tilstandstreet i henhold til handlingen som blir sendt til butikken.

Redux - http://redux.js.org/

Redux-thunk - https://github.com/gaearon/redux-thunk

Redux-saga - https://github.com/yelouafi/redux-saga

Svar #2

Den mest moteriktige måten er å bruke Redux.js (eller flux.js) for å opprettholde tilstanden til barnekomponentene dine.

http://redux.js.org/

Hvis du ikke liker å påkalle tredjeparts JS, kan du bruke refs-egenskapen:

https://facebook.github.io/react/docs/more-about-refs.html

Relaterte artikler