chevron-left chevron-right

[JS] Jak zaktualizować wygląd elementu po zmianie stanu atrybutu w React.js?

Ostatnio postanowiłem sprawdzić czym jest React.js? Od dłuższego czasu miałem świadomość istnienia tej biblioteki do obsługi widoków w aplikacjach JS. W trakcie testowania możliwości React.js napotkałem się z problemem aktualizacji widoku po zmianie stanu/wartości jednego z atrybutów widoku.

Problem polegał na tym, że w trakcie działania aplikacji postanowiłem aktualizować wartości wyświetlane w danym elemencie strony (na potrzeby tego tekstu załóżmy że był to licznik aktywnych użytkowników) a po aktualizacji wartości chciałem aby została uruchomiona animacja.

Szukałem rozwiązania tego problemu i okazało się (być może nie szukałem zbyt dokładnie), że React.js nie obsługuje możliwości zmiany stanu już istniejącego elementu. To znaczy, może zmieniać stan podczas dodawania elementu lub jego usuwania, ale w momencie gdy następuje aktualizacja danych, to implementacja zamierzonej animacji (chwilowe powiększenie elementu i powrót do poprzedniego wyglądu) jest niemożliwa.

Rozwiązanie problemu - aktualizacja wyglądu elementu po zmianie wartości atrybutu

Proponowane przeze mnie rozwiązanie opiera się na fakcie, że React.js monitoruje zmiany wartości klucza identyfikującego dany element - atrybut key. Gdy następuje zmiana wartości tego atrybutu, to React.js ponownie renderuje dany element.

Kod, który jest odpowiedzialny za takie działanie wygląda następująco:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
'use strict';
 
var React = require('../../../node_modules/react/addons'),
    ReactCSSTransitionGroup = React.addons.CSSTransitionGroup,
    NotificationItem;
 
(function () {
    NotificationItem = React.createClass({
        // Obsługa sytuacji, gdy następuje aktualizacja danych widoku
        // W tym przypadku, aktualizuje stan licznika liczby osób
        componentWillReceiveProps: function (nextProps) {
            this.setState({usersCount: nextProps.item.users.length});
        },
 
        getInitialState: function () {
            return {
                onClick: function () { console.log('notification:click'); },
                notificationType: 'default',
                updates: [],
                updatesCount: 0
            };
        },
 
        render: function () {
            var key = this.state.notificationType + '-notification-' + this.state.usersCount;
 
            return (
                <a className="notification" href="#" key={key} onClick={this.state.onClick}>
                    <ReactCSSTransitionGroup transitionName="update">
                        <span className="badge new">{this.state.usersCount}</span>
                    </ReactCSSTransitionGroup>
                </a>
            );
        }
    });
})();

Do powyższego kodu JavaScript możemy dołożyć kod CSS w którym będą zdefniowane reguły odpowiedzialne za animację, np.:

1
2
3
4
5
6
7
8
9
10
.notification {
    background: green;
    animation: notify .5s 2;
}
 
@keyframes notify {
    0% { transform: scale(0); }
    50% { transform: scale(1.5); }
    100% { transform: scale(1); }
}

W momencie gdy element zostanie od nowa wyrenderowany to animacja powinna się uruchomić.

Zapraszam do komentowania i dzielenia się swoimi uwagami.

  • No przecież to jest jedna ze świętych zasad Fluxa i Reacta: niemutowalność 😉

    „Od dłuższego czasu miałem świadomość istnienia tej biblioteki do obsługi widoków w aplikacjach JS” → gdyby React był wciąż tylko biblioteką do obsługi widoków to byłby świetnym i wydajnym systemem szablonów. Ale nagle React stał się bydlęciem od wszystkiego i stwarza realny problem.

    React nigdy mnie nie kupił prawdę powiedziawszy i drażni mnie to, co próbują webdevom wmówić devowie z fejsa – że wciśnięcie HTML-a i CSS w JS jest skalowalne, łatwiejsze w rozwoju i wgl… Otóż – nie, nie jest.

    Ostatnio o tym dyskutowałem na jednym forum – w ciut szerszym kontekście: http://forum.php.pl/Jaki_framework_biblioteka__t243181.html (oczywiście oberwało się przy okazji Angularowi ;))

    IMO najlepiej React podsumowały pandy: https://www.pandastrike.com/posts/20150311-react-bad-idea

    Osobiście bardziej mnie pociąga wizja asynchronicznego DOM: https://github.com/wilsonpage/fastdom