Piszę skrypt, który przesuwa się poniżej lub powyżej wejścia w zależności od wysokości rozwijanego menu i pozycji wejścia na ekranie. Chcę też ustawić modyfikator na rozwijany zgodnie z jego kierunkiem. Ale użycie setState
wewnątrz componentDidUpdate
tworzy nieskończoną pętlę (co jest oczywiste)
Znalazłem rozwiązanie w używaniu getDOMNode
i ustawianiu nazwy klasy bezpośrednio na liście rozwijanej, ale uważam, że powinno być lepsze rozwiązanie przy użyciu narzędzi React. Czy ktoś może mi pomóc?
Oto część działającego kodu z getDOMNode
(m.in. trochę zaniedbaną logiką pozycjonowania w celu uproszczenia kodu)
let SearchDropdown = React.createClass({
componentDidUpdate(params) {
let el = this.getDOMNode();
el.classList.remove('dropDown-top');
if(needToMoveOnTop(el)) {
el.top = newTopValue;
el.right = newRightValue;
el.classList.add('dropDown-top');
}
},
render() {
let dataFeed = this.props.dataFeed;
return (
<DropDown >
{dataFeed.map((data, i) => {
return (<DropDownRow key={response.symbol} data={data}/>);
})}
</DropDown>
);
}
});
a oto kod z setstate (który tworzy nieskończoną pętlę)
let SearchDropdown = React.createClass({
getInitialState() {
return {
top: false
};
},
componentDidUpdate(params) {
let el = this.getDOMNode();
if (this.state.top) {
this.setState({top: false});
}
if(needToMoveOnTop(el)) {
el.top = newTopValue;
el.right = newRightValue;
if (!this.state.top) {
this.setState({top: true});
}
}
},
render() {
let dataFeed = this.props.dataFeed;
let class = cx({'dropDown-top' : this.state.top});
return (
<DropDown className={class} >
{dataFeed.map((data, i) => {
return (<DropDownRow key={response.symbol} data={data}/>);
})}
</DropDown>
);
}
});
javascript
reactjs
ecmascript-6
Katerina Pavlenko
źródło
źródło
setState
że zawsze spowoduje to ponowne renderowanie. Zamiast sprawdzaćstate.top
i wywoływaćsetState
wiele razy, po prostu śledź, co chceszstate.top
znaleźć w zmiennej lokalnej, a następnie raz na końcucomponentDidUpdate
wywołaniasetState
tylko wtedy, gdy zmienna lokalna nie pasujestate.top
. W tej chwili resetujesz się natychmiaststate.top
po pierwszym ponownym renderowaniu, co umieszcza cię w nieskończonej pętli.componentDidUpdate
w tym skrzypce .componentShouldUpdate
?Odpowiedzi:
Możesz użyć w
setState
środkucomponentDidUpdate
. Problem polega na tym, że w jakiś sposób tworzysz nieskończoną pętlę, ponieważ nie ma warunku przerwania.Biorąc pod uwagę fakt, że potrzebujesz wartości, które są dostarczane przez przeglądarkę po wyrenderowaniu komponentu, myślę, że twoje podejście do używania
componentDidUpdate
jest poprawne, wymaga tylko lepszej obsługi warunku, który wyzwalasetState
.źródło
componentDidUpdate
irender
zamiast tego można je po prostu dodać w razie potrzeby .componentDidUpdate
Podpis jestvoid::componentDidUpdate(previousProps, previousState)
. Dzięki temu będziesz mógł przetestować, które właściwości / stan są brudne isetState
odpowiednio wywołać .Przykład:
źródło
componentDidMount
nie ma żadnych argumentów i jest wywoływana tylko podczas tworzenia komponentu, więc nie może być używana w opisanym celu.componentDidMount
, więc kiedy pisałem odpowiedź, słynne imię układało się kaskadowo 😮 Jeszcze raz, dzięki i świetne nadrabianie zaległości!componentDidUpdate(prevProps, prevState) { if ( prevState.x!== this.state.x) { //Do Something } }
Jeśli użyjesz
setState
wewnątrzcomponentDidUpdate
, aktualizuje komponent, powodując wywołanie,componentDidUpdate
które następnie wywołujesetState
ponownie, powodując nieskończoną pętlę. Powinieneś warunkowo zadzwonićsetState
i upewnić się, że stan naruszający wezwanie wystąpi w końcu, np .:W przypadku, gdy aktualizujesz komponent tylko przez wysłanie do niego właściwości (nie jest aktualizowany przez setState, z wyjątkiem przypadku wewnątrz komponentu componentDidUpdate), możesz wywołać
setState
insidecomponentWillReceiveProps
zamiastcomponentDidUpdate
.źródło
getDerivedStateFromProps
.Ten przykład pomoże ci zrozumieć hooki cyklu życia reakcji .
Możesz
setState
wgetDerivedStateFromProps
metodzie iestatic
wywołać metodę po zmianie właściwości wcomponentDidUpdate
.W
componentDidUpdate
dostaniesz trzeci parametr, który wraca zgetSnapshotBeforeUpdate
.Możesz sprawdzić ten kod link do skrzynki
źródło
Powiedziałbym, że musisz sprawdzić, czy stan ma już tę samą wartość, którą próbujesz ustawić. Jeśli jest taki sam, nie ma sensu ponownie ustawiać stanu dla tej samej wartości.
Upewnij się, że ustawiłeś swój stan w ten sposób:
źródło
Miałem podobny problem, w którym muszę wyśrodkować etykietkę narzędzia. Reakcja setState w komponencie componentDidUpdate umieściła mnie w nieskończonej pętli, próbowałem pod warunkiem, że zadziałało. Ale odkryłem, że użycie funkcji zwrotnej ref dało mi prostsze i czystsze rozwiązanie, jeśli użyjesz funkcji inline do wywołania zwrotnego ref, napotkasz problem zerowy dla każdej aktualizacji komponentu. Więc użyj odwołania do funkcji w wywołaniu zwrotnym ref i ustaw tam stan, który zainicjuje ponowne renderowanie
źródło