Mam aplikację, w której muszę dynamicznie ustawiać wysokość elementu (powiedzmy „zawartość aplikacji”). Bierze wysokość „chrome” aplikacji i odejmuje ją, a następnie ustawia wysokość „zawartości aplikacji”, aby zmieściła się w 100% w obrębie tych ograniczeń. Jest to bardzo proste w przypadku waniliowych widoków JS, jQuery lub Backbone, ale staram się dowiedzieć, jaki byłby właściwy proces, aby to zrobić w React?
Poniżej znajduje się przykładowy komponent. Chcę móc ustawić app-content
wysokość na 100% okna minus rozmiar ActionBar
i BalanceBar
, ale skąd mam wiedzieć, kiedy wszystko jest renderowane i gdzie powinienem umieścić obliczenia w tej klasie React?
/** @jsx React.DOM */
var List = require('../list');
var ActionBar = require('../action-bar');
var BalanceBar = require('../balance-bar');
var Sidebar = require('../sidebar');
var AppBase = React.createClass({
render: function () {
return (
<div className="wrapper">
<Sidebar />
<div className="inner-wrapper">
<ActionBar title="Title Here" />
<BalanceBar balance={balance} />
<div className="app-content">
<List items={items} />
</div>
</div>
</div>
);
}
});
module.exports = AppBase;
javascript
reactjs
Oscar Godson
źródło
źródło
Odpowiedzi:
componentDidMount ()
Ta metoda jest wywoływana raz po renderowaniu komponentu. Twój kod tak by wyglądał.
źródło
componentDidUpdate
jeśli wartości mogą ulec zmianie po pierwszym renderowaniu.componentDidMount()
nie powoduje przejścia.componentDidMount: () => { setTimeout(addClassFunction())}
lub użyj rAF, odpowiedź poniżej zapewnia tę odpowiedź.Wadą używania
componentDidUpdate
lubcomponentDidMount
jest to, że są one faktycznie wykonywane przed narysowaniem elementów dom, ale po ich przekazaniu z React do DOM przeglądarki.Powiedz na przykład, jeśli potrzebujesz ustawić node.scrollHeight na renderowanym node.scrollTop, to elementy DOM Reacta mogą być niewystarczające. Musisz poczekać, aż elementy zostaną pomalowane, aby uzyskać ich wysokość.
Rozwiązanie:
Użyj,
requestAnimationFrame
aby upewnić się, że kod jest uruchamiany po malowaniu nowo renderowanego obiektuźródło
_this.getDOMNode is not a function
co to do cholery jest ten kod?Z mojego doświadczenia
window.requestAnimationFrame
nie było wystarczające, aby zapewnić, że DOM został w pełni zrenderowany / przepełnionycomponentDidMount
. Mam uruchomiony kod, który uzyskuje dostęp do DOM natychmiast pocomponentDidMount
wywołaniu i użycie wyłączniewindow.requestAnimationFrame
spowoduje, że element będzie obecny w DOM; jednak aktualizacje wymiarów elementu nie są jeszcze odzwierciedlone, ponieważ nie nastąpiło jeszcze ponowne wycieki.Jedynym naprawdę niezawodnym sposobem na to było zawinięcie mojej metody w a
setTimeout
oraz a,window.requestAnimationFrame
aby upewnić się, że bieżący stos wywołań React zostanie wyczyszczony przed rejestracją do renderowania następnej ramki.Gdybym musiał spekulować, dlaczego tak się dzieje / jest to konieczne, mógłbym zobaczyć React wsadowe aktualizacje DOM i faktyczne stosowanie zmian do DOM dopiero po zakończeniu bieżącego stosu.
Ostatecznie, jeśli używasz pomiarów DOM w kodzie uruchamianym po wywołaniach zwrotnych React, prawdopodobnie będziesz chciał skorzystać z tej metody.
źródło
Aby zaktualizować nieco to pytanie za pomocą nowych metod haka, możesz po prostu użyć
useEffect
haka:Również jeśli chcesz uruchomić przed farbą układu, użyj
useLayoutEffect
haka:źródło
Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint.
.Możesz zmienić stan, a następnie wykonać obliczenia w wywołaniu zwrotnym setState . Zgodnie z dokumentacją React jest to „gwarantowane uruchomienie po zastosowaniu aktualizacji”.
Należy to zrobić w
componentDidMount
kodzie (lub w innym miejscu w kodzie) (jak w programie obsługi zmiany wielkości), a nie w konstruktorze.Jest to dobra alternatywa
window.requestAnimationFrame
i nie ma problemów, o których wspominali tutaj niektórzy użytkownicy (konieczność łączenia gosetTimeout
lub wywoływania go wiele razy). Na przykład:źródło
Wydaje mi się, że to rozwiązanie jest brudne, ale proszę bardzo:
Teraz po prostu usiądę tutaj i będę czekać na głosy negatywne.
źródło
React ma kilka metod cyklu życia, które pomagają w takich sytuacjach, listy obejmują między innymi getInitialState, getDefaultProps, componentWillMount, componentDidMount itp.
W twoim przypadku i przypadkach, które muszą wchodzić w interakcje z elementami DOM, musisz poczekać, aż dom będzie gotowy, więc użyj componentDidMount jak poniżej:
Aby uzyskać więcej informacji o cyklu życia w reakcji, możesz zajrzeć do poniższego linku: https://facebook.github.io/react/docs/state-and-lifecycle.html
źródło
Natrafiłem na ten sam problem.
W większości scenariuszy korzystania z hack-ish
setTimeout(() => { }, 0)
wcomponentDidMount()
zadziałało.Ale nie w szczególnym przypadku; i nie chciałem używać,
ReachDOM findDOMNode
ponieważ dokumentacja mówi:(Źródło: findDOMNode )
Więc w tym konkretnym komponencie musiałem użyć
componentDidUpdate()
zdarzenia, więc mój kod był taki:I wtedy:
Wreszcie w moim przypadku musiałem usunąć detektor utworzony w
componentDidMount
:źródło
Po renderowaniu możesz określić wysokość, jak poniżej, i możesz określić wysokość odpowiednich komponentów reagujących.
lub możesz określić wysokość każdego reagującego składnika za pomocą sass. Określ najpierw 2 główne działające elementy składowe o stałej szerokości, a następnie wysokość trzeciego głównego elementu składowego z auto. Zatem na podstawie zawartości trzeciego diva zostanie przypisana wysokość.
źródło
Mam problem z podobnym zachowaniem, renderuję element wideo w komponencie z jego atrybutem id, więc kiedy RenderDOM.render () kończy, ładuje wtyczkę, która potrzebuje identyfikatora, aby znaleźć symbol zastępczy i nie może go znaleźć.
SetTimeout z 0ms wewnątrz componentDidMount () to naprawił :)
źródło
Z dokumentacji ReactDOM.render () :
źródło
ReactDOM.render
, nie na poziomie składnikaReactElement.render
(co jest przedmiotem tutaj).Dla mnie brak połączenia
window.requestAnimationFrame
lubsetTimeout
spójne wyniki. Czasami działało, ale nie zawsze - a czasem byłoby za późno.Naprawiłem to, zapętlając
window.requestAnimationFrame
tyle razy, ile to konieczne.(Zazwyczaj 0 lub 2-3 razy)
Kluczem jest
diff > 0
: tutaj możemy zapewnić dokładnie, kiedy strona się aktualizuje.źródło
Miałem dziwną sytuację, kiedy musiałem wydrukować reagujący element, który otrzymuje dużą ilość danych i maluje na płótnie. Wypróbowałem wszystkie wymienione podejścia, żadne z nich nie działało dla mnie niezawodnie, z requestAnimationFrame wewnątrz setTimeout dostaję puste płótno w 20% czasu, więc zrobiłem następujące:
Zasadniczo stworzyłem łańcuch requestAnimationFrame, nie jestem pewien, czy to dobry pomysł, czy nie, ale jak dotąd działa to w 100% przypadków (używam 30 jako wartości zmiennej n).
źródło
W rzeczywistości jest o wiele prostsza i czystsza wersja niż używanie animacji ramki lub limitów czasu. Jestem zaskoczony, że nikt tego nie poruszył: moduł obsługi obciążenia waniliowego js. Jeśli możesz, skorzystaj z komponentu montowanego, jeśli nie, po prostu powiąż funkcję na hanlderze onload komponentu jsx. Jeśli chcesz, aby funkcja była uruchamiana przy każdym renderowaniu, uruchom ją również przed zwróceniem wyników w funkcji renderowania. kod wyglądałby tak:
}
źródło
Trochę aktualizacji z
ES6
klasami zamiastReact.createClass
Również - sprawdź Metody cyklu życia komponentów React: Cykl życia komponentów
Każdy komponent ma wiele metod podobnych do
componentDidMount
np.componentWillUnmount()
- element ma zostać usunięty z DOM przeglądarkiźródło