Konflikt interesów podczas event bubbling

0

@Edit
Rozwiązaniem wydaje się być dodanie:

// i jedno i drugie w tej kolejności
e.preventDefault()
e.stopPropagation()

w onTabClose o_O Jest może coś mniej dziwnego?


**@Edit2** Dowiedziałem się, ze react rerenderuje dopiero w momencie zakończenia eventu. To by wyjaśniało dlaczego dochodzi do nadpisania. Teraz pytanie, **czy ten błąd jest związany z tym, że błędnie zaimplementowałem tą funkcjonalność** i problem nie powinien wystąpić, gdy np. zrobie to po bożemu i wykorzystam reduxa, czy tak po prostu musi być i trzeba skorzystać np. z rozwiązania wyżej?
**Problem** Implementuję otwieranie zakładek (chatów z poszczególnymi osobami) i ich zamykanie.

Selection_006.png
Problem pojawia się w momencie, w którym klikając na X, event onClick bąbelkuje również na moją zakładkę. przez co wywołuje drugi handler (który również modyfikuje state). Z tego co udało mi się dowiedzieć, to wbrew pozorom setState działa asynchronicznie, przez co drugi handler nadpisuje state nieaktualnymi danymi.

Może to te cztery linijki lepiej zobrazują problem.
Po kliknięciu w X (oczywiście gdyby wszystko poszło zgodnie z założeniami, po onTabClose tablica records powinna mieć 1 element)

bundle.js:19826 onTabClose beforeSetState Object {key: 2, records: Array[2]} 
bundle.js:19810 onTabSelect beforeSetState Object {key: 2, records: Array[2]} 
bundle.js:19841 render
bundle.js:19833 onTabClose - setStateCallback Object {key: 2, records: Array[2]}
bundle.js:19814 onTabSelect - setStateCallback Object {key: 2, records: Array[2]}

Próbowałem coś zadziałać z e.stopPropagation(), ale okazuje się, że react ma swoje własne eventy i nie bardzo to chce działać, bo np. przeładowuje mi stronę o_O. Mogę nie używać spread operatora w onTabSelect, ale to za dużo nie pomoże, bo o ile ustawi się zakładka, to key pozostanie stary. Minimalna implementacja problemu znajduje się tutaj

@LukeJL, @Maciej Cąderek
Jak będziecie mieli wolną chwilę, to prośba, o rzut okiem. Mam już kilka rozwiązań, ale takich na około, ale niestety nadal nie rozumiem czemu tak to działa.

0

Błąd jest tutaj:

    onTabSelect(key) {
        this.setState({
            ...this.state,
            key: key
        })
    }

Zmieniasz tylko key (swoją droga fatalna nazwa dla aktywnego tab'a) więc niepotrzebnie dajesz "...this.state". Zatem ta funkcja powinna wyglądać tak:

    onTabSelect(key) {
        this.setState({ key })
    }
0

@k4wo to tylko szkic, stąd te robocze nazwy. Natomiast to nie rozwiązuje problemu. Faktycznie tab się zamyka, ale nadpisuje się klucz. Event bąbelkuje w górę (w tym wypadku react nie rerenderuje komponentu od razu, tylko dopiero jak event dojdzie do konca) i wywołując onSelect na tabie ze starym kluczem nadpisuje poprzednie setState.

Pozostaje zatrzymanie eventu w dosyć smieszny sposób.

Oczywiście problem rozwiązał się sam jak to przepisałem jak Bóg przykazał z użycem Reduxa, ale przynajmniej sie co nie co dowiedziałem o systemie eventów reacta.

0

Nie bardzo rozumiem co masz na myśli nadpisuje się klucz. Bo z tego co widzę, to tak zaprojektowałeś aplikację.

this.setState({
	key: key - 1,
	records: records.filter(r => r.id !== record.id)
})
0

@k4wo już tłumacze. Załóżmy, że w state wygląda tak:

{
    key: 2,
    records: [
        {id: 1},
        {id: 2}
    ]
}

Czyli mamy dwie zakładki, z czego druga jest aktywna. Gdy kliknę w X wywołany zostanie handler onTabClose, który usunie z records odpowiedni wpis i zmodyfukuje klucz na key - 1. State teraz powinien wyglądać tak:

{
    key: 1,
    records: [
        {id: 1}
    ]
}

Ale nie wygląda (tzn. wygląda, ale przez ułamek sekundy). React w momencie wywołania setState nie rerenderuje komponentu od razu, jeżeli event jest w trakcie bąbelkowania.
W tym momencie w konsekwencji event bubbling zostaje odpalony handler na zakładce onTabSelect ze starym kluczem i nadpisuje on state. Na koniec otrzymujemy wynik:

{
    key: 2,
    records: [
        {id: 1}
    ]
}

Dlatego podwójne zatrzymanie eventu (tak jak napisałem w pierwszym poście) działa. Nie wiem czemu, ale działa. Po prostu zatrzymuje event i handler onTabSelect nie jest nigdy wywołany.

1 użytkowników online, w tym zalogowanych: 0, gości: 1